目录
一、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-3000GET 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/_searchDELETE person_index_v2