ElasticSearch进阶小记

 

目录

一、ik分词器

1.1 指定ik分词器

1.2 使用ik分词器

二、批量操作文档

2.1 脚本实现

2.2 api实现

三、查询(重点)

3.1 matchAll

3.1.1 脚本使用

3.1.1 api使用

3.2 termQuery

3.2.1 脚本使用

 3.2.2 api使用

3.3 matchQuery 

3.3.1 脚本使用

3.3.2 api使用

3.4 模糊查询

3.4.1 脚本使用

3.4.1.1 wildcard查询

3.4.1.2 regexp查询

3.4.1.3 perfix查询

 3.4.1 api使用

3.5 范围查询&排序

3.5.1 脚本使用

3.5.2 api使用

 3.6 queryString查询

3.6.1 脚本使用

3.6.2 api使用 

 3.7 布尔查询 

 3.7.1 脚本使用

 3.7.2 api使用

3.8 聚合查询

3.8.1 指标聚合

3.8.1.1 脚本使用

3.8.1.2 api使用

3.8.2 桶聚合

3.8.2.1 脚本使用

3.8.2.2 api使用

3.9 高亮查询 

3.9.1 脚本使用

3.9.2 api使用

四、索引别名和重建索引

4.1 重建索引

4.2 索引别名


一、ik分词器

1.1 指定ik分词器

es的默认分词器为Standard分词器,默如果要使用ik分词器,需要在建立映射时对需要分词的字段指定ik分词器

注:ik分词器有两种模式,ik_smart与ik_max_word模式,ik_smart为粗粒度模式,ik_max_word为细粒度模式.

PUT person
{
  "mappings": {
    "properties": {
      "id":{
        "type": "keyword"
      },
      "name":{
        "type": "keyword"
      },
      "address":{
        "type": "text",
        "analyzer": "ik_max_word" //指定ik分词器
      }
    }
  }
}

1.2 使用ik分词器

使用ik分词器进行查询有两个方式,term与match,term不会对查询条件进行分词操作,只用当查询条件与词条完全匹配才能查出该条数据,而match会对查询条件进行分词,将查询条件分词后再与词条匹配求并集.

GET person/_search
{
  "query": {
    "term": {
      "address": {
        "value": "四川省重庆市海淀区青石街"
      }
    }
  }
}

==============结果=================

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  }
}

GET person/_search
{
  "query": {
    "match": {
      "address": "四川省重庆市海淀区青石街"
    }
  }
}

==============结果=================

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : 10.341532,
    "hits" : [
      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 10.341532,
        "_source" : {
          "id" : "4",
          "name" : "马可波罗",
          "address" : "我住在四川省重庆市海淀区青石街"
        }
      },
      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 3.7050552,
        "_source" : {
          "id" : "2",
          "name" : "韩信",
          "address" : "我住在江苏省南京市海淀区青石街"
        }
      },
      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.21917993,
        "_source" : {
          "id" : "1",
          "name" : "李白",
          "address" : "我住在安徽省合肥市瑶海区粑粑路"
        }
      },
      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.21236017,
        "_source" : {
          "id" : "3",
          "name" : "吕布",
          "address" : "我住在安徽省合肥市庐江县粑粑区"
        }
      }
    ]
  }
}

二、批量操作文档

2.1 脚本实现

#语法
POST _bulk
{"action":{"metadata"}}
{"data"}

示例:

POST _bulk
{"delete":{"_index":"student","_id":"1"}}
{"create":{"_index":"student","_id":"4"}}
{"name":"赵六","age":18,"address":"浙江省绍兴市海淀区青石街"}
{"update":{"_index":"student","_id":"2"}}
{"doc":{"name":"王老五"}}

注:批量操作中的update,当更新某一字段时, 不会影响其他字段,即其他字段保持原状,而在使用

PUT student/_doc/1
{
  "name" : "Mr.三"
},这种方式更新文档时,原有的其他字段会被置空.

2.2 api实现

package com.motionlesstar.controller;

import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@RestController
public class BatchController {

    @Autowired
    private RestHighLevelClient client;

    /**
     * 批量操作bulk
     * @throws IOException
     */
    @GetMapping("/bulk")
    public void bulk() throws IOException {
        //获取批量操作对象
        BulkRequest bulkRequest = new BulkRequest();
        //1.删除id为1的数据
        DeleteRequest deleteRequest = new DeleteRequest("student","1");
        bulkRequest.add(deleteRequest);
        //2.新增id为6的数据
        Map map = new HashMap();
        map.put("name","孙7");
        map.put("age",19);
        map.put("addre","广东省深圳市海淀区青石街");
        IndexRequest indexRequest = new IndexRequest("student").id("6").source(map);
        bulkRequest.add(indexRequest);
        //3.修改id为4的数据
        Map map2 = new HashMap();
        map2.put("name","赵老六");
        UpdateRequest updateRequest = new UpdateRequest("student","4").doc(map2);
        bulkRequest.add(updateRequest);

        BulkResponse responses = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(responses.status());
    }
}

三、查询(重点)

3.1 matchAll

3.1.1 脚本使用

作用:查询所有文档

语法:

GET goods/_search
{
  "query": {
    "match_all": {}
  }
}

注:查询所有文档时,es默认展示前10条数据,当然也可以自定义展示

GET goods/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0, //从哪条数据开始
  "size": 20 //每页数据大小
}

3.1.1 api使用

package com.motionlesstar.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.motionlesstar.model.pojo.Goods;
import com.motionlesstar.dao.GoodsMapper;
import com.motionlesstar.service.IGoodsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author motionlesstar
 * @since 2024-03-15
 */
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements IGoodsService {

    @Autowired
    private RestHighLevelClient client;

    /**
     * 查询所有
     * 1.matchAll
     * 2.将查询结果封装为goods对象,装载到list中
     * 3.分页.默认显示10条数据
     */
    public void matchAllGoods() throws IOException {
        //2.构建查询对象,指定查询的索引名称
        SearchRequest searchRequest = new SearchRequest("goods");
        //4.创建查询条件构建器
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //条件构造器添加分页
        sourceBuilder.from(0);
        sourceBuilder.size(20);
        //6.组装查询条件
        QueryBuilder query = QueryBuilders.matchAllQuery();//查询所有文档
        //5.条件构建器添加查询条件
        sourceBuilder.query(query);
        //3.添加查询条件构建器
        searchRequest.source(sourceBuilder);
        //searchRequest.source(SearchSourceBuilder.searchSource());
        //1.查询获取结果
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        //7.组装结果
        SearchHits hits = response.getHits();
        //7.1获取总条数
        TotalHits totalHits = hits.getTotalHits();
        long value = totalHits.value;
        System.out.println(value);
        //7.2获取数据
        SearchHit[] hitsHits = hits.getHits();
        List<Goods> goods = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (SearchHit hitsHit : hitsHits) {
            String sourceAsString = hitsHit.getSourceAsString();
            Goods readValue = objectMapper.readValue(sourceAsString, Goods.class);
            goods.add(readValue);
        }
        for (Goods good : goods) {
            System.out.println(good);
        }
    }
}

3.2 termQuery

3.2.1 脚本使用

GET goods/_search
{
  "query": {
    "term": {
      "title": {
        "value": "华为"
      }
    }
  },
  "from": 0,
  "size": 20
}

 3.2.2 api使用

/**
     * termQuery查询
     * @throws IOException
     */
    public void termQueryGoods() throws IOException {
        SearchRequest searchRequest = new SearchRequest("goods");
        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
        QueryBuilder query =QueryBuilders.termQuery("title","华为");
        sourceBuilder.query(query);
        searchRequest.source(sourceBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = response.getHits().getHits();
        List<Goods> list = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (SearchHit hit : hits) {
            Goods goods = objectMapper.readValue(hit.getSourceAsString(), Goods.class);
            list.add(goods);
        }

        for (Goods goods : list) {
            System.out.println(goods);
        }
    }

3.3 matchQuery 

  • 会对查询条件进行分词
  • 然后将分词后的查询条件和词条进行等值匹配
  • 默认取并集(or)

注:这里取并集的意思是,例如查询条件为华为手机,会先将华为手机进行分词,华为  手机,然后数据里的title字段如果有华为或者有手机都会查出来;如果要取交集,意思是title字段内必须含有华为和手机,才被查询出来,求交集需要修改operator字段改成and,该字段默认为or

3.3.1 脚本使用

GET goods/_search
{
  "query": {
    "match": {
      "title": "华为手机"
    }
  }
}

==============================================

GET goods/_search
{
  "query": {
    "match": {
      "title": {
        "query": "华为手机",
        "operator": "and"
      }
    }
  }
}

3.3.2 api使用

/**
     * matchQuery查询
     * @throws IOException
     */
    public void matchQueryGoods() throws IOException {
        SearchRequest searchRequest = new SearchRequest("goods");
        SearchSourceBuilder searchSourceBuiler =  SearchSourceBuilder.searchSource();
        MatchQueryBuilder query = QueryBuilders.matchQuery("title", "华为手机");
        //设置交集或并集
        query.operator(Operator.AND);
        //query.operator(Operator.OR);
        searchSourceBuiler.query(query);
        searchRequest.source(searchSourceBuiler);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits num = response.getHits();
        TotalHits totalHits = num.getTotalHits();
        long value = totalHits.value;
        System.out.println(value);
        SearchHit[] hits = response.getHits().getHits();
        List<Goods> list = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (SearchHit hit : hits) {
            Goods goods = objectMapper.readValue(hit.getSourceAsString(), Goods.class);
            list.add(goods);
        }

        for (Goods goods : list) {
            System.out.println(goods);
        }
    }

3.4 模糊查询

3.4.1 脚本使用

3.4.1.1 wildcard查询

wildcard查询会对查询条件进行分词.还可以使用通配符?(任意单个字符) 和*(0个或多个字符)

 GET goods/_search
{
  "query": {
    "wildcard": {
      "title": {
        "value": "华?" 注:"value": "华?" 与 "value": "华*" 前者通配词条华后面只有一个字,后者通配华后面无字或多个字
      }
    }
  }
}

3.4.1.2 regexp查询

正则查询

GET goods/_search
{
  "query": {
    "regexp": {
      "title": "\\w+(.)*"
    }
  }
}

3.4.1.3 perfix查询

前缀查询

注:这种查询更实用与keyword类型字段,若是下面的term查询肯定查不到,此时换成prefix就可以查到了

GET goods/_search
{
  "query": {
    "prefix": {
      "brandname": {
        "value": "三"
      }
    }
  }
}

================================

GET goods/_search
{
  "query": {
    "term": {
      "brandname": {
        "value": "三"
      }
    }
  }
}

 3.4.1 api使用

public void fuzzyQueryGoods() throws IOException {
        SearchRequest searchRequest = new SearchRequest("goods");
        SearchSourceBuilder searchBuilder =  SearchSourceBuilder.searchSource();
        //通配查询
        QueryBuilder query = QueryBuilders.wildcardQuery("title","华?");
        //正则查询
        //QueryBuilder query = QueryBuilders.regexpQuery("title","\\w+(.)*");
        //前缀查询
        //QueryBuilder query = QueryBuilders.prefixQuery("brandname","三");
        searchBuilder.query(query);
        searchRequest.source(searchBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits num = response.getHits();
        TotalHits totalHits = num.getTotalHits();
        long value = totalHits.value;
        System.out.println(value);
        SearchHit[] hits = response.getHits().getHits();
        List<Goods> list = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (SearchHit hit : hits) {
            Goods goods = objectMapper.readValue(hit.getSourceAsString(), Goods.class);
            list.add(goods);
        }

        for (Goods goods : list) {
            System.out.println(goods);
        }
    }

3.5 范围查询&排序

range范围查询:查找指定字段在指定范围内包含值

3.5.1 脚本使用

GET goods/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 10,
        "lte": 20
      }
    }
  }
}

==================================

GET goods/_search
{
  "query": {
    "range": {
      "price": {
        "gt": 11,
        "lt": 20
      }
    }
  }
}

GET goods/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 10,
        "lte": 2000
      }
    }
  },
  "sort": [
    {
      "price": {
        "order": "desc"
      }
    }
  ]

3.5.2 api使用

public void rangeQueryGoods() throws IOException {
        SearchRequest searchRequest = new SearchRequest("goods");
        SearchSourceBuilder searchBuilder =  SearchSourceBuilder.searchSource();
        //排序
        searchBuilder.sort("price", SortOrder.DESC);
        //范围查询
        RangeQueryBuilder query = QueryBuilders.rangeQuery("price");
        query.gte(10);
        query.lte(2000);
        searchBuilder.query(query);
        searchRequest.source(searchBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits num = response.getHits();
        TotalHits totalHits = num.getTotalHits();
        long value = totalHits.value;
        System.out.println(value);
        SearchHit[] hits = response.getHits().getHits();
        List<Goods> list = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (SearchHit hit : hits) {
            Goods goods = objectMapper.readValue(hit.getSourceAsString(), Goods.class);
            list.add(goods);
        }

        for (Goods goods : list) {
            System.out.println(goods);
        }

    }

 3.6 queryString查询

  • 会对查询条件进行分词(注:也可以手动进行分词,但必须使用query_string,simple_query_string没有手动分词的功能)
  • 然后将分词后的查询条件和词条进行等值匹配
  • 默认如并集(OR)
  • 可以指定多个字段

3.6.1 脚本使用

GET goods/_search
{
  "query": {
    "query_string": {
      "fields": ["title","categoryName","brandName"],
      "query": "华为 AND手机"  注:这里如果进行手动分词时,AND 和OR必须大写,小写无效
    }
  }
}

3.6.2 api使用 

/**
     * queryString多字段查询
     */
    public void queryStringGoods() throws IOException {
        SearchRequest searchRequest = new SearchRequest("goods");
        SearchSourceBuilder searchBuilder =  SearchSourceBuilder.searchSource();
        //范围查询
        QueryStringQueryBuilder query = QueryBuilders.queryStringQuery("华为 OR 手机");
        query.field("title").field("categoryName").field("brandName");
        searchBuilder.query(query);
        searchRequest.source(searchBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits num = response.getHits();
        TotalHits totalHits = num.getTotalHits();
        long value = totalHits.value;
        System.out.println(value);
        SearchHit[] hits = response.getHits().getHits();
        List<Goods> list = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (SearchHit hit : hits) {
            Goods goods = objectMapper.readValue(hit.getSourceAsString(), Goods.class);
            list.add(goods);
        }

        for (Goods goods : list) {
            System.out.println(goods);
        }

    }

 3.7 布尔查询 

boolQuery:对多个查询条件连接.连接方式:

  • must(and):条件必须成立
  • must_not(not):条件必须不成立
  • should(or):条件可以成立
  • filter:条件必须成立,性能比must高.不会计算得分

注:得分可以理解为查询条件与词条的匹配度,相同的部分越多,得分越高

语法:GET goods/_search
{
  "query": {
    "bool": {
      "must": [
        {}
      ],
      "must_not": [
        {}
      ],
      "should": [
        {}
      ],
      "filter": [{}]
    }
  }
}

 3.7.1 脚本使用

GET goods/_search
{
  "query": {
    "bool": {
      "must": [
        {"match": {
          "title": "华为手机"
        }},
        {
          "term": {
            "categoryname.keyword": {
              "value": "手机"
            }
          }
        }
      ],
      "filter": {
        "term": {
          "brandname.keyword": "华为"
        }
      },
      "should": [
        {"match": {
          "title": "电信4G手机"
        }},
        {
          "term": {
            "title": {
              "value": "电信"
            }
          }
        }
      ],
      "must_not": [
        {"match": {
          "title": "电信"
        }},
        {"term": {
          "title": {
            "value": "白色"
          }
        }}
      ]
    }
  }
}

======================================

 *1.查询品牌名称为:华为
 * 2.查询标题包含:手机
 * 3.查询价格在:2000-3000

GET goods/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "brandname.keyword": {
            "value": "华为"
          }
        }}
      ],
      "filter": [
        {"match": {
          "title": "手机"
        }},
        {"range": {
          "price": {
            "gte": 2000,
            "lte": 3000
          }
        }}
      ]
    }
  }
}

 3.7.2 api使用

/**
     * 布尔查询
     * 1.查询品牌名称为:华为
     * 2.查询标题包含:手机
     * 3.查询价格在:2000-3000
     * @throws IOException
     */
    public void boolQueryGoods() throws IOException {
        SearchRequest searchRequest = new SearchRequest("goods");
        SearchSourceBuilder searchBuilder =  SearchSourceBuilder.searchSource();
        //布尔查询
        //构建boolquery
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        TermQueryBuilder termQuery = QueryBuilders.termQuery("brandname.keyword", "华为");
        boolQuery.must(termQuery);
        MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("title", "手机");
        boolQuery.filter(matchQuery);
        RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");
        rangeQuery.gte(2000);
        rangeQuery.lte(3000);
        boolQuery.filter(rangeQuery);
        searchBuilder.query(boolQuery);
        searchRequest.source(searchBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits num = response.getHits();
        TotalHits totalHits = num.getTotalHits();
        long value = totalHits.value;
        System.out.println(value);
        SearchHit[] hits = response.getHits().getHits();
        List<Goods> list = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (SearchHit hit : hits) {
            Goods goods = objectMapper.readValue(hit.getSourceAsString(), Goods.class);
            list.add(goods);
        }

        for (Goods goods : list) {
            System.out.println(goods);
        }
    }

3.8 聚合查询

3.8.1 指标聚合

相当于MySQL的聚合查询.max、min、avg、sum等

3.8.1.1 脚本使用

#指标聚合
GET goods/_search
{
  "query": {
    "match": {
      "title": "手机"
    }
  },
  "aggs": {
    "max_price": {
      "min": {
        "field": "price"
      }
    }
  }
}

3.8.1.2 api使用
/**
     * 聚合函数
     */
    public void aggregateQueryGoods() throws IOException {
        SearchRequest searchRequest = new SearchRequest("goods");
        SearchSourceBuilder searchBuilder =  SearchSourceBuilder.searchSource();
        MatchQueryBuilder query = QueryBuilders.matchQuery("title", "手机");
        searchBuilder.query(query);
        //构建聚合条件器
        //AggregationBuilder agg = AggregationBuilders.max("max_price").field("price");
        AggregationBuilder agg = AggregationBuilders.min("max_price").field("price");
        searchBuilder.aggregation(agg);

        searchRequest.source(searchBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits num = response.getHits();
        TotalHits totalHits = num.getTotalHits();
        long value = totalHits.value;
        System.out.println(value);
        SearchHit[] hits = response.getHits().getHits();
        List<Goods> list = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (SearchHit hit : hits) {
            Goods goods = objectMapper.readValue(hit.getSourceAsString(), Goods.class);
            list.add(goods);
        }

        for (Goods goods : list) {
            System.out.println(goods);
        }
        //获取聚合结果
        Aggregations aggregations = response.getAggregations();
        //Max max_price = aggregations.get("max_price");
        Min max_price = aggregations.get("max_price");
        double maxPriceValue = max_price.getValue();
        System.out.println(maxPriceValue);
    }

3.8.2 桶聚合

相当于MySQL的group by操作.不要对text类型的数据进行分组,会导致失败

3.8.2.1 脚本使用

#桶聚合
GET goods/_search
{
  "query": {
    "term": {
      "title": {
        "value": "手机"
      }
    }
  },
  "aggs": {
    "goods_brandname": {
      "terms": {
        "field": "brandname.keyword",
        "size": 100
      }
    }
  }
}

3.8.2.2 api使用
/**
     * 分组函数
     */
    public void bucketQueryGoods() throws IOException {
        SearchRequest searchRequest = new SearchRequest("goods");
        SearchSourceBuilder searchBuilder =  SearchSourceBuilder.searchSource();
        MatchQueryBuilder query = QueryBuilders.matchQuery("title", "手机");
        searchBuilder.query(query);
        //构建分组条件器
        AggregationBuilder agg = AggregationBuilders.terms("goods_brandname").field("brandname.keyword").size(100);
        searchBuilder.aggregation(agg);

        searchRequest.source(searchBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits num = response.getHits();
        TotalHits totalHits = num.getTotalHits();
        long value = totalHits.value;
        System.out.println(value);
        SearchHit[] hits = response.getHits().getHits();
        List<Goods> list = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (SearchHit hit : hits) {
            Goods goods = objectMapper.readValue(hit.getSourceAsString(), Goods.class);
            list.add(goods);
        }

        for (Goods goods : list) {
            System.out.println(goods);
        }
        //获取桶聚合结果
        Aggregations aggregations = response.getAggregations();
        Map<String, Aggregation> stringAggregationMap = aggregations.asMap();
        Terms goods_brandname = (Terms) stringAggregationMap.get("goods_brandname");
        List<? extends Terms.Bucket> buckets = goods_brandname.getBuckets();
        List name = new ArrayList();
        for (Terms.Bucket bucket : buckets) {
            Object key = bucket.getKey();
            name.add(key);
        }
        for (Object o : name) {
            System.out.println(o);
        }
    }

3.9 高亮查询 

高亮三要素:

  • 高亮字段
  • 前缀
  • 后缀

3.9.1 脚本使用

#高亮显示
GET goods/_search
{
  "query": {
    "match": {
      "title": "手机"
    }
  },
  "highlight": {
    "fields": {
      "title": {
        "pre_tags": "<font color='red'>",
        "post_tags": "</font>"
      }
    }
  }
}

效果: 

 

3.9.2 api使用

/**
     * 高亮查询
     * @throws IOException
     */
    public void highlightQueryGoods() throws IOException {
        SearchRequest searchRequest = new SearchRequest("goods");
        SearchSourceBuilder searchBuilder =  SearchSourceBuilder.searchSource();
        MatchQueryBuilder query = QueryBuilders.matchQuery("title", "手机");
        searchBuilder.query(query);
        //设置高亮
        HighlightBuilder highlighter =  new  HighlightBuilder();
        //设置三要素
        highlighter.field("title");
        //注:这里前后缀不设置也行,默认使用<em></em>
        highlighter.preTags("<font color='red'>");
        highlighter.postTags("</font>");
        searchBuilder.highlighter(highlighter);

        searchRequest.source(searchBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits num = response.getHits();
        TotalHits totalHits = num.getTotalHits();
        long value = totalHits.value;
        System.out.println(value);
        SearchHit[] hits = response.getHits().getHits();
        List<Goods> list = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (SearchHit hit : hits) {
            Goods goods = objectMapper.readValue(hit.getSourceAsString(), Goods.class);
            //获取高亮字段,替换goods中的对应地段
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField highlightField = highlightFields.get("title");
            //分片
            Text[] fragments = highlightField.fragments();
            //替换
            goods.setTitle(fragments[0].toString());
            list.add(goods);
        }

        for (Goods goods : list) {
            System.out.println(goods);
        }
    }

效果: 

四、索引别名和重建索引

4.1 重建索引

背景:随着业务的变更,某个索引结构需要更改,但是es的索引被创建后,只允许添加字段,不允许改变字段或删除字段.解决方法是:重建一个新的索引,将原索引数据导入新建的索引中.

#原索引
PUT person_index_v1
{
  "mappings": {
    "properties": {
      "birthday":{
        "type": "date"
      }
    }
  }
}

PUT person_index_v1/_doc/1
{
  "birthday":"1995-12-19"
}
PUT person_index_v1/_doc/2
{
  "birthday":"1996-01-09"
}

#数据转移分两步
#1.新建索引
PUT person_index_v2
{
  "mappings": {
    "properties": {
      "birthday":{
        "type": "keyword"
      }
    }
  }
}
#2._reindex拷贝数据
POST _reindex
{
  "source": {
    "index": "person_index_v1"
  },
  "dest": {
    "index": "person_index_v2"
  }
}

4.2 索引别名

在4.1中,我们将person_index_v1中的数据迁移到person_index_v2中,但是我们的代码中还是使用person_index_v1的索引名,如何解决?

方式1:改代码,重新编译部署上线(不推荐)

方式2:索引别名

注:1.给索引库起别名时,如果该别名是另一个索引库名,需要将该索引库删除,否则起别名失败

     2.起别名后,原索引库名和别名索引库名都可查到数据,但删除时只能使用原索引库名

#起别名_alias

POST person_index_v2/_alias/person_index_v1

GET person_index_v1/_search
GET person_index_v2/_search

DELETE person_index_v2


  • 28
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值