ElasticSearch
DreamCollector一、引入依赖
Elasticsearch_v7.10为基础开发,采用高级REST客户端,详请参考:官网
1 2 3 4 5
| <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.10.0</version> </dependency>
|
二、相关概念
Mysql |
Elasticsearch |
数据库(database) |
索引(indices) |
表(tables) |
types |
行(rows) |
documents |
字段(columns) |
fields |
三、 API
使用时注入高版本client
1 2
| @Autowired private RestHighLevelClient esClient;
|
1. 索引API
1.1. 创建索引
1 2 3 4 5 6 7 8
| CreateIndexRequest request = new CreateIndexRequest(ES_INDEX); CreateIndexResponse createIndexResponse = esClient.indices().create(request, RequestOptions.DEFAULT); if (createIndexResponse.equals(ES_INDEX)) { System.out.println("创建索引成功"); } else { System.out.println("创建索引失败"); }
|
1.2. 判断索引是否存在
1 2 3 4 5 6 7
| GetIndexRequest getIndexRequest = new GetIndexRequest(ES_INDEX); boolean exists = esClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT); if (exists) { System.out.println("索引存在"); } else { System.out.println("索引不存在"); }
|
1.3. 获取索引
1 2 3
| GetIndexRequest getIndexRequest = new GetIndexRequest(ES_INDEX); GetIndexResponse getIndexResponse = esClient.indices().get(getIndexRequest, RequestOptions.DEFAULT); System.out.println(getIndexResponse.getAliases());
|
1.4. 删除索引
1 2 3 4 5 6 7
| DeleteIndexRequest deleteRequest = new DeleteIndexRequest(ES_INDEX); AcknowledgedResponse acknowledgedResponse = esClient.indices().delete(deleteRequest, RequestOptions.DEFAULT); if (acknowledgedResponse.isAcknowledged()) { System.out.println("删除索引成功"); } else { System.out.println("删除索引失败"); }
|
2. 文档API
2.1. 添加文档
1 2 3 4 5
| User user = new User().setUserName("李四").setAge(21); IndexRequest indexRequest = new IndexRequest(ES_INDEX); indexRequest.id("1").source(JSON.toJSONString(user), XContentType.JSON); IndexResponse indexResponse = esClient.index(indexRequest, RequestOptions.DEFAULT); System.out.println(indexResponse.toString());
|
2.2. 判断文档是否存在
1 2 3 4 5 6 7
| GetRequest getRequest = new GetRequest(ES_INDEX, "1"); boolean exists = esClient.exists(getRequest, RequestOptions.DEFAULT); if (exists) { System.out.println("存在"); } else { System.out.println("不存在"); }
|
2.3. 获取文档
1 2 3
| GetRequest getRequest = new GetRequest(ES_INDEX, "1"); GetResponse documentFields = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT); System.out.println(documentFields.getSourceAsString());
|
2.4. 更新文档
1 2 3 4 5 6 7 8 9
| UpdateRequest updateRequest = new UpdateRequest(ES_INDEX, "1"); User user = new User().setUserName("李四").setAge(21); updateRequest.doc(JSON.toJSONString(user), XContentType.JSON); UpdateResponse updateResponse = esClient.update(updateRequest, RequestOptions.DEFAULT); if (updateResponse.status().getStatus() == 200) { System.out.println("更新文档成功"); } else { System.out.println("更新文档失败"); }
|
2.5. 删除文档
1 2 3 4 5 6 7
| DeleteRequest deleteRequest = new DeleteRequest(ES_INDEX, "1"); DeleteResponse deleteResponse = esClient.delete(deleteRequest, RequestOptions.DEFAULT); if (deleteResponse.status().getStatus() == 200) { System.out.println("删除文档成功"); } else { System.out.println("删除文档失败"); }
|
3. 复杂查询API
3.1. 精准查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| SearchRequest searchRequest = new SearchRequest(ES_INDEX);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("userName.keyword", "李四"); searchSourceBuilder.query(termQueryBuilder);
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
searchSourceBuilder.from(1); searchSourceBuilder.size(10); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
List<User> userList = new ArrayList<>(); for (SearchHit hit : searchResponse.getHits().getHits()) { userList.add(JSON.parseObject(hit.getSourceAsString(), User.class)); } userList.forEach(item -> System.out.println(item));
|
3.2. 多字段查询同一结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.size(1); QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("search", "userName", "userNameEN"); searchSourceBuilder.query(queryBuilder); SearchRequest searchRequest = new SearchRequest("ES_INDEX").source(searchSourceBuilder); SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT); List<User> userList = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) { userList.add(JSON.parseObject(hit.getSourceAsString(), User.class)); }
userList.forEach(item -> System.out.println(item));
|
3.3. 多字段查询不同结果
1 2 3 4 5 6 7 8 9 10
| SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
QueryBuilder userName= QueryBuilders.matchPhraseQuery("userName","张三"); QueryBuilder userNameEN= QueryBuilders.matchPhraseQuery("userNameEN", "ZhangSan");
QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(userName).must(userNameEN); searchSourceBuilder.query(queryBuilder); SearchRequest searchRequest = new SearchRequest("ES_INDEX").source(searchSourceBuilder);
|
3.4. 高亮查询(需安装插件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| SearchRequest searchRequest = new SearchRequest(ES_INDEX);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("userName.keyword", "李四"); searchSourceBuilder.query(termQueryBuilder);
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
searchSourceBuilder.from(1); searchSourceBuilder.size(10);
searchSourceBuilder.sort("age", SortOrder.DESC);
HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("userName"); highlightBuilder.preTags("<span style='color: red;'>"); highlightBuilder.postTags("</span>"); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT); List<User> userList = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) { userList.add(JSON.parseObject(hit.getSourceAsString(), User.class)); }
userList.forEach(item -> System.out.println(item));
|
四、HTTP请求
mapping是对索引库中文档的约束,常见的mapping属性包括:
type:字段数据类型,常见的简单类型有:
- 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
- 数值:long、integer、short、byte、double、float
- 布尔:boolean
- 日期:date
- 对象:object
- fields:
多字段属性
(让一个字段拥有多个子字段类型,使得一个字段能够被多个不同的索引方式进行索引)
- index:是否创建索引(此索引非前面所说的索引库,),默认为true
- analyzer:使用哪种分词器
- properties:该字段的子字段
1. 索引请求
1.1. 创建索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| PUT /{索引名} { "mappings": { "properties": { "comic_id": { "type": "keyword" }, "comic_source": { "type": "keyword" }, "comic_name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 #表示最大的字段值长度,*超出这个长度的字段将不会被索引,但是会存储,ignore_above一般设置为256 } } }, "author_name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "comic_label": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "comic_cover": { "type": "keyword" }, "comic_status": { "type": "keyword" } } } }
|
1.2. 查询索引
1.3. 修改索引库
索引库一旦创建,无法修改mapping
1.4. 添加索引库
1 2 3 4 5 6 7 8
| PUT /{索引名}/_mapping { "properties": { "新字段名":{ "type": "integer" } } }
|
1.4. 删除索引库(删表)
2. 文档请求
2.1. 添加文档
没有指定文档id的话,es会随机给你生成一个新的id(是不规则的随机字符串,例:wXxbyYuBVgHo5bYKF1Jc)
1 2 3 4 5 6 7 8 9 10
| POST /{索引名}/_doc/{文档id} { "字段1": "值1", "字段1": "值2", "字段1": { "子属性1": "值3" "子属性1": "值4", }, }
|
2.2. 获取文档
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| GET /{索引名}/_doc/{文档id} { "_index" : "comic", # 表面文档所在索引库 "_type" : "_doc", "_id" : "1", "_version" : 1, #版本控制,每做一次版本修改就会自增 "_seq_no" : 0, "_primary_term" : 1, "found" : true, "_source" : { #插入原始文档 "info" : "大天才是小瘦子", "number" : "123456", "name" : { "firstName" : "瘦子", "lastName" : "小" } } }
|
2.3. 删除文档
1
| DELETE /{索引名}/_doc/{文档id}
|
2.4. 修改文档
全量修改,若PUT命令的文档 id不存在则会进行文档创建,且只修改个别字段,其余未修改的字段数据会被删除
1 2 3 4 5 6 7 8 9 10
| PUT /{索引名}/_doc/{文档id} { "字段1": "值1", "字段1": "值2", "字段1": { "子属性1": "值3" "子属性1": "值4", }, }
|
增量修改,修改指定字段则不会有以上的问题
1 2 3 4 5 6
| POST /{索引名}/_update/{文档id} { "doc":{ "字段名":"新的值", } }
|
3. 复杂请求
3.1. 模糊查询
指定查询类型 |
描述 |
match |
等同于like模糊查询,match查询的字段如果是text类型,那么text会被分词查询,否则为精准查询 |
match_all |
查询所有的数据,ES默认分页为10条数据,这个关键字不能写查询条件 |
match_phrase |
匹配短语,match是会查询所有包含分词的doc文档,而match_phrase则是匹配整个短语,才会返回对应的doc文档 |
match_phrase_prefix |
匹配短语前缀部分,且只能使用在text类型字段 |
1 2 3 4 5 6 7 8 9 10
| GET /{索引名}/_search { "query": { "match": { "name": "张三" } }, "_source": ["查询字段1", "查询字段2"] }
|
过滤字段
- _source: [“查询字段1”, “查询字段2”] 只返回指定的字段
- source=false 所有字段都不返回
3.2. 布尔查询
指定条件类型 |
描述 |
must |
等同于and ,所有条件为must中的数组->[a,b]=a and b |
should |
等同于or ,所有条件为must中的数组->[a,b]=a or b |
must_not |
等同于! 、not ->where not 查询字段=值 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| GET /{索引名}/_search { "query": { "bool": { "must": [ "match": { "name": "张三" }, "查询类型": { "查询字段": "查询值" } ] } } }
|
3.3. 范围查询
- 条件:
gt
:大于
lt
:小于
gte
:大于等于
lte
:小于等于
eq
:等于
ne
:不等于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| GET /{索引名}/_search { "query": { "bool": { "filter": [ { "range": { "指定字段": { "条件": "范围值", "条件": "范围值" } } } ] } } }
|
3.4. 判断文档字段值是否为空
exists
是否存在exists用在filter
里面时候,表示过滤掉不存在指定字段的doc文档,等同于is null
注意:exists会返回指定字段存在的doc文档,只有当字段等于null,即:不存在时候才会匹配成功,如果字段等于空字符串不会匹配成功。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| GET /{索引名}/_search { "query": { "bool": { "filter": [ { "exists": { "查询字段": "查询值" } } ] } } }
|
3.5. 文档ids过滤查询
ids过滤查询,只能够对doc文档的id进行多个值查询,等同于ids in(”2022001”,”2022005”)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| GET /{索引名}/_search { "query": { "bool": { "filter": [ { "ids": { "values": [ "2022001", "2022005" ] } } ] } } }
|
3.6. term精准关键词查询
term关键词查询,等同于like “字段值%”,用于精准查询,不会像math一样分词拆解来查询
注意:term每次只能够匹配一个关键字,但terms允许多个关键字匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| GET /{索引名}/_search { "query": { "bool": { "filter": [ {
"terms": { "查询字段": [ "查询值1", "查询值2", "查询值3", ] } } ] } } }
|