• ElasticSearch 04 -- 进阶


    上一篇:ElasticSearch 03 -- 基础使用_fengxianaa的博客-CSDN博客

    1. 批量操作

    使用 _bulk 命令,是es提供的一种批量增删改的操作API

    bulk对JSON串有着严格的要求:每个JSON串一行

    1. POST _bulk
    2. {"delete":{"_index":"hero","_id":"3"}}
    3. {"create":{"_index":"hero","_id":"4"}}
    4. {"name":"西施","skill":"最有价值之物,给最珍贵之人"}
    5. {"update":{"_index":"person","_id":"2"}}
    6. {"doc":{"skill":"让妲己看看你的心"}}

    解释:

    • {"delete":{"_index":"hero","_id":"3"}}:删除id是3的数据
    • {"create":{"_index":"hero","_id":"4"}}:添加数据,内容是:{"name":"西施","skill":"最有价值之物,给最珍贵之人"}
    • {"update":{"_index":"hero","_id":"2"}}:更新数据,内容是:{"doc":{"skill":"让妲己看看你的心"}}

    结果:id=3的已经删除掉,成功添加 id=4 的数据,成功修改 id=2 的数据

    使用 java API:

    1. private static void bulk() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. //1. 组装bulk请求对象
    5. BulkRequest bulkRequest = new BulkRequest();
    6. //1.1 删除id=4的文档
    7. DeleteRequest delReq = new DeleteRequest("hero","4");
    8. bulkRequest.add(delReq);
    9. //1.2 创建id=5的文档
    10. Map<String,Object> map = new HashMap<>();
    11. map.put("name","甄姬");
    12. map.put("skill","小女子尚在阵前,大丈夫却要回城?");
    13. IndexRequest createDoc = new IndexRequest("hero")//hero 是索引名
    14. .id("5")//指定id
    15. .source(map);//参数也可以螫map
    16. bulkRequest.add(createDoc);
    17. //1.3 更新id=1的文档
    18. Map<String,Object> map2 = new HashMap<>();
    19. map2.put("skill","没有心,就不会受伤");
    20. //更新数据也可以使用UpdateRequest,更新指定字段
    21. UpdateRequest updateRequest = new UpdateRequest("hero","2");
    22. updateRequest.doc(map2);
    23. bulkRequest.add(updateRequest);
    24. BulkResponse responses = client.bulk(bulkRequest, RequestOptions.DEFAULT);
    25. //输出每个请求的执行结果
    26. for(BulkItemResponse item : responses.getItems()){
    27. System.out.println(item.status());
    28. }
    29. client.close();
    30. }

    Kibana查询:id=4 的已经删除掉,成功添加 id=5 的数据,成功修改 id=2 的数据

    使用场景:批量导入数据库中的数据

    1. private static void importData() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. BulkRequest bulkRequest = new BulkRequest();
    5. for(int i =6;i<100;i++){
    6. Map<String,Object> map = new HashMap<>();
    7. map.put("name","嫦娥_" + i);
    8. map.put("skill","像做梦一样");
    9. IndexRequest createDoc = new IndexRequest("hero")//hero 是索引名
    10. .id(i + "")//指定id
    11. .source(map);//参数也可以螫map
    12. bulkRequest.add(createDoc);
    13. }
    14. BulkResponse responses = client.bulk(bulkRequest, RequestOptions.DEFAULT);
    15. System.out.println(responses.status());
    16. client.close();
    17. }

    2. 查询--重点

    1. 查询所有数据

    1. Kibana上脚本使用
    1. # 标准写法
    2. GET hero/_search
    3. {
    4. "query": {
    5. "match_all": {}
    6. }
    7. }
    8. # 非标准:GET person/_search

    但是 ES 默认返回10条数据,当然也可以指定返回的条数

    1. # from:从哪里开始,size:指定返回的条数,可以用这俩参数做分页查询
    2. GET hero/_search
    3. {
    4. "query": {
    5. "match_all": {}
    6. },
    7. "from": 0,
    8. "size": 3
    9. }

    1. java API
    1. private static void queryAll() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. //1. 创建请求对象
    5. SearchRequest request = new SearchRequest("hero");// hero:索引名
    6. //1.1 查询条件构造器
    7. SearchSourceBuilder builder = new SearchSourceBuilder();
    8. //1.2 组装查询条件,目前是查询所有
    9. builder.query(QueryBuilders.matchAllQuery());
    10. //1.3 设置分页条件
    11. builder.from(0);
    12. builder.size(5);
    13. //1.4 把查询条件放到requst中
    14. request.source(builder);
    15. //2. 发送查询请求
    16. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    17. //3. 拿到返回结果
    18. SearchHits hits = response.getHits();
    19. //3.1 输出总条数
    20. System.out.println("一共有:" + hits.getTotalHits().value + " 条数据");
    21. //3.2 取出数据内容
    22. SearchHit[] arr = hits.getHits();
    23. for(SearchHit hit : arr){
    24. String content = hit.getSourceAsString();//以字符串形式获取数据内容
    25. System.out.println(content);
    26. }
    27. client.close();
    28. }

    结果:

    2. term查询

    使用“term”查询,不会对关键字分词,适合查询类型是“keyword”的字段

    1. GET hero/_search
    2. {
    3. "query": {
    4. "term": {
    5. "name": {
    6. "value": "亚瑟"
    7. }
    8. }
    9. }
    10. }

    结果:

    java API

    1. private static void termQuery() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. SearchRequest request = new SearchRequest("hero");// hero:索引名
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. // term查询,使用 termQuery 方法
    7. builder.query(QueryBuilders.termQuery("name","亚瑟"));
    8. builder.from(0);
    9. builder.size(5);
    10. request.source(builder);
    11. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    12. SearchHits hits = response.getHits();
    13. System.out.println("一共有:" + hits.getTotalHits().value + " 条数据");
    14. SearchHit[] arr = hits.getHits();
    15. for(SearchHit hit : arr){
    16. String content = hit.getSourceAsString();//以字符串形式获取数据内容
    17. System.out.println(content);
    18. }
    19. client.close();
    20. }

    结果:

    3. match 查询

    先更新一条数据

    1. POST hero/_doc/2
    2. {
    3. "name":"妲己",
    4. "skill":"王者荣耀,没有心,就不会受伤"
    5. }

    会对查询的关键字分词,然后用分词后的结果分别查询,最后取并集

    1. # match查询
    2. GET hero/_search
    3. {
    4. "query": {
    5. "match": {
    6. "skill": "王者不可阻挡"
    7. }
    8. }
    9. }

    结果:

    因为“王者不可阻挡”的分词结果是:王者、不可、阻挡

    查询时,根据:王者、不可、阻挡,分别查询,最后再获取并集,所以结果是2条

    但是有时,需要最终结果中同时包含:王者、不可、阻挡,这 3 个词

    1. # match查询,取交集
    2. GET hero/_search
    3. {
    4. "query": {
    5. "match": {
    6. "skill": {
    7. "query": "王者不可阻挡",
    8. "operator": "and"
    9. }
    10. }
    11. }
    12. }

    分别查询后,取交集,结果:

    Java API

    1. private static void matchQuery() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. SearchRequest request = new SearchRequest("hero");// hero:索引名
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. // match 查询,使用 matchQuery 方法
    7. builder.query(QueryBuilders.matchQuery("skill","王者不可阻挡").operator(Operator.AND));
    8. builder.from(0);
    9. builder.size(5);
    10. request.source(builder);
    11. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    12. SearchHits hits = response.getHits();
    13. System.out.println("一共有:" + hits.getTotalHits().value + " 条数据");
    14. SearchHit[] arr = hits.getHits();
    15. for(SearchHit hit : arr){
    16. String content = hit.getSourceAsString();//以字符串形式获取数据内容
    17. System.out.println(content);
    18. }
    19. client.close();
    20. }

    结果:

    4. 模糊查询

    1. 问题

    执行下面命令:

    1. # match查询
    2. GET hero/_search
    3. {
    4. "query": {
    5. "match": {
    6. "skill": {
    7. "query": "王"
    8. }
    9. }
    10. }
    11. }

    发现一个结果都没有

    这是因为:

    1. 我们存进去的数据经过分词后,没有“王”这个词
    2. 目前我们用的是等值查询

    所以,没有结果

    2. wildcard

    对查询的关键字分词,还可以使用通配符进行模糊查询

    • ?:代表任意单个字符
      • 王?:匹配 ES 的词条中以“王”开头,2个字的词条
    • *:代表0个或多个字符
      • 王*:匹配 ES 的词条中以“王”开头的词条
    1. # wildcard 模糊查询
    2. GET hero/_search
    3. {
    4. "query": {
    5. "wildcard": {
    6. "skill": {
    7. "value": "王?"
    8. }
    9. }
    10. }
    11. }

    java

    1. private static void wildcard() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. SearchRequest request = new SearchRequest("hero");// hero:索引名
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. // match 查询,使用 matchQuery 方法
    7. builder.query(QueryBuilders.wildcardQuery("skill","王?"));
    8. builder.from(0);
    9. builder.size(5);
    10. request.source(builder);
    11. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    12. SearchHits hits = response.getHits();
    13. System.out.println("一共有:" + hits.getTotalHits().value + " 条数据");
    14. SearchHit[] arr = hits.getHits();
    15. for(SearchHit hit : arr){
    16. String content = hit.getSourceAsString();//以字符串形式获取数据内容
    17. System.out.println(content);
    18. }
    19. client.close();
    20. }

    结果:

    3. 正则

    利用正则表达式去查询,只做了解

    一个不错的正则网站:regex101: build, test, and debug regex

    1. # 正则表达式查询
    2. GET hero/_search
    3. {
    4. "query": {
    5. "regexp": {
    6. "skill": ".*荣耀"
    7. }
    8. }
    9. }

    结果:

    4. 前缀查询

    前缀查询也是一般用于“keyword”类型的字段

    1. # 前缀查询
    2. GET hero/_search
    3. {
    4. "query": {
    5. "prefix": {
    6. "name": {
    7. "value": "嫦娥_"
    8. }
    9. }
    10. }
    11. }

    5. java API

    1. private static void likeQuery() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. SearchRequest request = new SearchRequest("hero");// hero:索引名
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. // wildcard 查询,使用 wildcardQuery 方法
    7. // builder.query(QueryBuilders.wildcardQuery("hero","王?"));
    8. // 正则查询,使用 regexpQuery 方法
    9. // builder.query(QueryBuilders.regexpQuery("hero",".*荣耀"));
    10. // 前缀查询,使用 prefixQuery 方法
    11. builder.query(QueryBuilders.prefixQuery("name","嫦娥_"));
    12. builder.from(0);
    13. builder.size(5);
    14. request.source(builder);
    15. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    16. SearchHits hits = response.getHits();
    17. System.out.println("一共有:" + hits.getTotalHits().value + " 条数据");
    18. SearchHit[] arr = hits.getHits();
    19. for(SearchHit hit : arr){
    20. String content = hit.getSourceAsString();//以字符串形式获取数据内容
    21. System.out.println(content);
    22. }
    23. client.close();
    24. }

    5. 范围查询

    范围查询也是很常见的操作,比如:

    目前我们的数据不支持范围查询,所以重新导入一些

    1. private static void importData() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. BulkRequest bulkRequest = new BulkRequest();
    5. for(int i =6;i<100;i++){
    6. Map<String,Object> map = new HashMap<>();
    7. map.put("name","嫦娥_" + i);
    8. map.put("skill","像做梦一样");
    9. map.put("skill_num", i);//增加一个字段
    10. IndexRequest createDoc = new IndexRequest("hero")//hero 是索引名
    11. .id(i + "")//指定id
    12. .source(map);//参数也可以螫map
    13. bulkRequest.add(createDoc);
    14. }
    15. BulkResponse responses = client.bulk(bulkRequest, RequestOptions.DEFAULT);
    16. System.out.println(responses.status());
    17. client.close();
    18. }
    1. Kibana脚本
    1. # 范围查询
    2. GET hero/_search
    3. {
    4. "query": {
    5. "range": {
    6. "skill_num": {
    7. "gte": 6,
    8. "lte": 7
    9. }
    10. }
    11. }
    12. }
    13. # 查询 skill_num>=6 && skill_num<=7 的数据
    14. # 查询 skill_num>6的数据,应该这样写:"gt": 6,

    1. java API
    1. private static void rangeQuery() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. SearchRequest request = new SearchRequest("hero");// hero:索引名
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. // 范围查询,使用 rangeQuery 方法
    7. builder.query(QueryBuilders.rangeQuery("skill_num").gte(6).lte(7));
    8. builder.from(0);
    9. builder.size(5);
    10. request.source(builder);
    11. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    12. SearchHits hits = response.getHits();
    13. System.out.println("一共有:" + hits.getTotalHits().value + " 条数据");
    14. SearchHit[] arr = hits.getHits();
    15. for(SearchHit hit : arr){
    16. String content = hit.getSourceAsString();//以字符串形式获取数据内容
    17. System.out.println(content);
    18. }
    19. client.close();
    20. }

    1. 排序

    根据范围查询一般都会排个序

    1. # 范围查询
    2. GET hero/_search
    3. {
    4. "query": {
    5. "range": {
    6. "skill_num": {
    7. "gte": 6,
    8. "lte": 7
    9. }
    10. }
    11. },
    12. "sort": [
    13. {
    14. "skill_num": {
    15. "order": "desc"
    16. }
    17. }
    18. ]
    19. }
    20. # desc 降序

    java API

    1. private static void rangeQuery() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. SearchRequest request = new SearchRequest("hero");// hero:索引名
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. // 范围查询,使用 rangeQuery 方法
    7. builder.query(QueryBuilders.rangeQuery("skill_num").gte(6).lte(7));
    8. builder.from(0);
    9. builder.size(5);
    10. // 排序
    11. builder.sort("skill_num", SortOrder.DESC);
    12. request.source(builder);
    13. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    14. SearchHits hits = response.getHits();
    15. System.out.println("一共有:" + hits.getTotalHits().value + " 条数据");
    16. SearchHit[] arr = hits.getHits();
    17. for(SearchHit hit : arr){
    18. String content = hit.getSourceAsString();//以字符串形式获取数据内容
    19. System.out.println(content);
    20. }
    21. client.close();
    22. }

    6. 多字段查询

    上面我们都是查询单个字段,其实也可以同时查询多个字段

    1. queryString

    • 对查询关键字分词,然后用分词后的结果分别查询,最后取并集
    • 可以指定查询多个字段
    1. 查询多个字段
    1. # 分词后,查询多个字段
    2. GET hero/_search
    3. {
    4. "query": {
    5. "query_string": {
    6. "fields": ["skill","name"],
    7. "query": "亚瑟的荣耀",
    8. "analyzer": "ik_max_word"
    9. }
    10. }
    11. }

    1. 手动对关键字分词
    1. # 分词后,查询多个字段
    2. GET hero/_search
    3. {
    4. "query": {
    5. "query_string": {
    6. "fields": ["skill","name"],
    7. "query": "亚瑟 AND 荣耀",
    8. "analyzer": "ik_max_word"
    9. }
    10. }
    11. }
    12. # "亚瑟 AND 荣耀":结果中要同时包含 亚瑟 和 荣耀 这两个词条
    13. # "亚瑟 OR 荣耀":结果中要包含 亚瑟 或 荣耀

    2. sampleQueryString

    它跟 queryString 的区别是:不支持 OR、AND 这样的连接符

    1. # simple_query_string
    2. GET hero/_search
    3. {
    4. "query": {
    5. "simple_query_string": {
    6. "fields": ["skill","name"],
    7. "query": "亚瑟 AND 荣耀",
    8. "analyzer": "ik_max_word"
    9. }
    10. }
    11. }
    12. # "亚瑟 AND 荣耀":会切分成 亚瑟 AND 荣耀 3个词, 然后分别查询,最后取并集

    返回两个结果

    3. java API

    1. private static void queryString() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. SearchRequest request = new SearchRequest("hero");// hero:索引名
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. // queryString 查询,使用 queryStringQuery 方法
    7. // builder.query(QueryBuilders.queryStringQuery("亚瑟的荣耀")
    8. // .field("skill").field("name").analyzer("ik_max_word"));
    9. // simpleQueryString 查询,使用 simpleQueryStringQuery 方法
    10. builder.query(QueryBuilders.simpleQueryStringQuery("亚瑟 AND 荣耀").field("skill").field("name").analyzer("ik_max_word"));
    11. request.source(builder);
    12. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    13. SearchHits hits = response.getHits();
    14. System.out.println("一共有:" + hits.getTotalHits().value + " 条数据");
    15. SearchHit[] arr = hits.getHits();
    16. for(SearchHit hit : arr){
    17. String content = hit.getSourceAsString();//以字符串形式获取数据内容
    18. System.out.println(content);
    19. }
    20. client.close();
    21. }

    7. 布尔查询

    连接多个查询条件,比如:

    关键字:

    • must: 条件必须成立
    • must_not: 条件必须不成立
    • should: 条件可以不成立
    • filter: 条件必须成立,但是性能比 must高,因为不计算分数

    默认情况下,ES 会给查询到的结果计算分数,得分高的放到前面

    1. 查询 name="亚瑟",skill 包含 “王者” 的数据
    1. GET hero/_search
    2. {
    3. "query": {
    4. "bool": {
    5. "must": [
    6. {
    7. "term": {
    8. "name": {
    9. "value": "亚瑟"
    10. }
    11. }
    12. },
    13. {
    14. "match": {
    15. "skill":"王者"
    16. }
    17. }
    18. ]
    19. }
    20. }
    21. }

    1. 配合 filter 使用
    1. # 查询 skill 包含 “王者”,name="妲己",的数据
    2. GET hero/_search
    3. {
    4. "query": {
    5. "bool": {
    6. "must": [
    7. {
    8. "match": {
    9. "skill": "王者"
    10. }
    11. }
    12. ],
    13. "filter": [
    14. {
    15. "term": {
    16. "name": "妲己"
    17. }
    18. }
    19. ]
    20. }
    21. }
    22. }

    1. should 条件可以不成立
    1. # 查询 name=亚瑟 或 老亚瑟 的 数据
    2. GET hero/_search
    3. {
    4. "query": {
    5. "bool": {
    6. "should": [
    7. {
    8. "term": {
    9. "name": {
    10. "value": "亚瑟"
    11. }
    12. }
    13. },
    14. {
    15. "term": {
    16. "name":{
    17. "value": "老亚瑟"
    18. }
    19. }
    20. }
    21. ]
    22. }
    23. }
    24. }

    1. Java API
    1. private static void boolQuery() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. SearchRequest request = new SearchRequest("hero");// person:索引名
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. // bool 查询,使用 boolQuery 方法
    7. builder.query(QueryBuilders.boolQuery()
    8. .must(QueryBuilders.matchQuery("skill","王者"))
    9. .filter(QueryBuilders.termQuery("name","妲己")));
    10. request.source(builder);
    11. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    12. SearchHits hits = response.getHits();
    13. System.out.println("一共有:" + hits.getTotalHits().value + " 条数据");
    14. SearchHit[] arr = hits.getHits();
    15. for(SearchHit hit : arr){
    16. String content = hit.getSourceAsString();//以字符串形式获取数据内容
    17. System.out.println(content);
    18. }
    19. client.close();
    20. }

    8. 聚合查询

    分为两种:

    • 指标聚合:类似数据库中的:max、min、avg、sum等函数
    • 分组:类似数据库中的 group by

    重新生成数据

    1. DELETE hero
    2. # 创建索引,并添加映射
    3. PUT hero
    4. {
    5. "mappings": {
    6. "properties": {
    7. "id":{
    8. "type": "integer"
    9. },
    10. "name":{
    11. "type":"keyword"
    12. },
    13. "skill":{
    14. "type":"text"
    15. },
    16. "skill_num":{
    17. "type": "integer"
    18. },
    19. "type":{
    20. "type": "keyword"
    21. }
    22. }
    23. }
    24. }
    25. POST _bulk
    26. {"create":{"_index":"hero","_id":"1"}}
    27. {"id":1,"name":"亚瑟","skill":"王者,以圣剑的名义,冲锋","skill_num":3,"type":"战士"}
    28. {"create":{"_index":"hero","_id":"2"}}
    29. {"id":2,"name":"妲己","skill":"王者,没有心,就不会受伤","skill_num":3,"type":"法师"}
    30. {"create":{"_index":"hero","_id":"3"}}
    31. {"id":3,"name":"甄姬","skill":"王者,还人间一片净土","skill_num":3,"type":"法师"}
    32. {"create":{"_index":"hero","_id":"4"}}
    33. {"id":4,"name":"西施","skill":"王者,最有价值之物,给最珍贵之人","skill_num":3,"type":"法师"}
    34. GET hero/_search
    1. 指标聚合
    1. # 查询 skill 中包含 王者 的数据,并拿到结果中最大的skill_num
    2. GET hero/_search
    3. {
    4. "query": {
    5. "match": {
    6. "skill": "王者"
    7. }
    8. },
    9. "aggs": {
    10. "max_skill_num": {
    11. "max": {
    12. "field": "skill_num"
    13. }
    14. }
    15. }
    16. }
    17. # "max_skill_num" 是自己定义的字段名,之后会在结果中展示

    1. 分组
    1. # 查询所有数据,并对结果中的 type 进行分组,取分组后的前10条数据
    2. GET hero/_search
    3. {
    4. "query": {
    5. "match_all": {}
    6. },
    7. "aggs": {
    8. "type_group": {
    9. "terms": {
    10. "field": "type",
    11. "size": 10
    12. }
    13. }
    14. }
    15. }

    1. Java API
    1. private static void aggQuery() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. SearchRequest request = new SearchRequest("hero");// hero:索引名
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. builder.query(QueryBuilders.matchAllQuery());
    7. /**
    8. * 组装聚合条件
    9. * name_group:自定义的名字,获取数据使用
    10. * name:分组的字段名
    11. */
    12. AggregationBuilder aggBuilder = AggregationBuilders.terms("type_group").field("type").size(10);
    13. builder.aggregation(aggBuilder);
    14. request.source(builder);
    15. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    16. // 获取聚合结果
    17. Aggregation groupResult = response.getAggregations().asMap().get("type_group");
    18. // 获取分组结果,需要把 groupResult 转换为 Term
    19. List<? extends Terms.Bucket> buckets = ((Terms) groupResult).getBuckets();
    20. for(Terms.Bucket bucket : buckets){
    21. System.out.println(bucket.getKey() + "----" + bucket.getDocCount());
    22. }
    23. client.close();
    24. }

    9. 结果高亮

    让查询的结果高亮显示,比如:

    其实本质就是设置了一个样式

    1. Kibana演示
    1. # 对查询结果高亮
    2. GET hero/_search
    3. {
    4. "query": {
    5. "match": {
    6. "skill": "王者荣耀"
    7. }
    8. },
    9. "highlight": {
    10. "fields": {
    11. "skill": {
    12. "pre_tags": "<font color='red'>",
    13. "post_tags": "</font>"
    14. }
    15. }
    16. }
    17. }

     

    1. Java API
    1. private static void highLight() throws IOException {
    2. RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    3. new HttpHost("192.168.56.109",9200,"http")));
    4. SearchRequest request = new SearchRequest("hero");// hero:索引名
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. builder.query(QueryBuilders.matchQuery("skill","王者荣耀"));
    7. //设置高亮条件
    8. HighlightBuilder highlightBuilder = new HighlightBuilder();
    9. highlightBuilder.field("skill").preTags("<font color='red'>").postTags("</font>");
    10. builder.highlighter(highlightBuilder);
    11. request.source(builder);
    12. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    13. SearchHits hits = response.getHits();
    14. System.out.println("一共有:" + hits.getTotalHits().value + " 条数据");
    15. SearchHit[] arr = hits.getHits();
    16. for(SearchHit hit : arr){
    17. //获取高亮结果
    18. Map<String, HighlightField> highlightFields = hit.getHighlightFields();
    19. //拿到高亮的字段
    20. HighlightField addressField = highlightFields.get("skill");
    21. //获取高亮的数据,是一个数组,我们文档比较简单,取数组的第一个就行了
    22. String address = addressField.getFragments()[0].string();
    23. Map<String, Object> map = hit.getSourceAsMap();
    24. //用高亮的数据替换查询到的结果
    25. map.put("skill", address);
    26. System.out.println(map);
    27. }
    28. client.close();
    29. }

    3. 索引重建

    随着业务的发展,索引的结构可能发生变化。但是 ES 规定,一旦索引创建就只能添加字段,不能修改字段

    因为改变字段需要重建:倒排索引,性能太低。

    ES提供了另一种方式:重建索引,并把老的索引数据导入到新的索引中

    演示:

    1. # 1. 新建一个 student1 索引,只有一个 birth 字段,date类型
    2. PUT student1
    3. {
    4. "mappings": {
    5. "properties": {
    6. "birth":{
    7. "type": "date"
    8. }
    9. }
    10. }
    11. }
    12. # 2. 存储一条数据
    13. PUT student1/_doc/1
    14. {
    15. "birth":"2000-01-01"
    16. }

    这时候业务变更,birth字段需要存储 “2000年1月1日”,这样的字符串,如果还用老的索引结构会报错

    1. PUT student1/_doc/2
    2. {
    3. "birth":"2000年1月1日"
    4. }

    并且 ES 也不支持修改字段类型

    这时候只能重建索引

    1. # 1. 建立一个新的索引:student2, 设置 birth 为 text 类型
    2. PUT student2
    3. {
    4. "mappings": {
    5. "properties": {
    6. "birth":{
    7. "type": "text"
    8. }
    9. }
    10. }
    11. }
    12. # 2. 导入老的索引数据
    13. POST _reindex
    14. {
    15. "source": {
    16. "index": "student1"
    17. },
    18. "dest": {
    19. "index": "student2"
    20. }
    21. }
    22. # 3. 存放一条数据
    23. PUT student2/_doc/2
    24. {
    25. "birth":"2000年1月1日"
    26. }
    27. # 4. 查询数据
    28. GET student2/_search

    查询 student2 的数据

    但是这时,我们代码中用的还是老索引名,再修改代码明显不现实

    ES 提供了给索引设置别名,来解决这种问题:

    • 删除老的索引
    • 给新的索引设置别名
    1. # 1. 删除老索引
    2. DELETE student1
    3. # 2. 给新的索引设置别名
    4. POST student2/_alias/student1
    5. # 3. 通过别名也能查询到数据
    6. GET student1/_search


     

  • 相关阅读:
    企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图
    SpringBoot 使用 Sa-Token 完成注解鉴权功能
    详解Shiro认证流程
    Windows PowerShell 和 Linux BashShell 极简对比
    2021 OWASP TOP 10 漏洞指南
    自学(网络安全)黑客——高效学习2024
    刚毕业的学长真实体验:2022年软件测试行业不再吃香?毕业即失业?
    区间统计——ST算法
    React的Render的简单实现
    Java基础进阶多线程-四种创建方式
  • 原文地址:https://blog.csdn.net/fengxianaa/article/details/125569958