欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > [ElasticSearch] DSL查询

[ElasticSearch] DSL查询

2025/6/8 0:54:06 来源:https://blog.csdn.net/2301_80050796/article/details/148458573  浏览:    关键词:[ElasticSearch] DSL查询

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (93平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(97平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(96平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
🎃Redis(97平均质量分)https://blog.csdn.net/2301_80050796/category_12777129.html?spm=1001.2014.3001.5482
🐰RabbitMQ(97平均质量分) https://blog.csdn.net/2301_80050796/category_12792900.html?spm=1001.2014.3001.5482
💻 项目总结(97平均质量分) https://blog.csdn.net/2301_80050796/category_12936070.html?spm=1001.2014.3001.5482
🎈JVM(97平均质量分) https://blog.csdn.net/2301_80050796/category_12976744.html?spm=1001.2014.3001.5482
🔍ElasticSearch(96平均质量分) https://blog.csdn.net/2301_80050796/category_12978995.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~

在这里插入图片描述

目录

  • 1. DSL查询
    • 1.1 快速入门
    • 1.2 叶子查询
      • 1.2.1 全文检索查询
      • 1.2.2 精确查询
    • 1.3 复合查询
      • 1.3.1 算分函数查询
      • 1.3.2 bool查询
    • 1.4 排序
    • 1.5 分页
      • 1.5.1 基础分页
      • 1.5.2 深度分页
    • 1.6 高亮
      • 1.6.1 高亮显示原理
      • 1.6.2 实现高亮
    • 1.7 总结
  • 2. RestClient查询
    • 2.1 快速入门
      • 2.2.1 发送请求
      • 2.1.2 解析响应结果
      • 2.1.3 总结
    • 2.2 叶子查询
    • 2.3 复合查询
    • 2.4 排序和分页
    • 2.5 高亮

今天我们来研究以下ElasticSearch的数据搜索功能,ElasticSearch提供了基于json的DSL语句来定义查询条件,其javaAPI就是在组织DSL条件.
因此我们先学习DSL的查询语法,在基于DSL来对照学习javaAPI,就会事半功倍.

1. DSL查询

ElasticSearch的查询可以分为两大类:

  • 叶子查询: 一般是在特定的字段里查询特定的值,属于简单查询,很少单独使用.
  • 复合查询: 以逻辑方式组合多个叶子查询或者更改叶子查询的行为方式.

1.1 快速入门

我们依然在Kibana的DevTools中学习查询的DSL语法,首先来看查询的语法结构:

GET /{索引库名}/_search
{"query": {"查询类型": {// .. 查询条件}}
}

说明: GET /{索引库名}/_search: 其中的_search是固定路径,不能更改.

例如,我们以最简单的无条件查询,无条件查询的类型是: match_all,因此查询语句如下:

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

由于match_all无条件,所以条件位置不写即可.
执行结果如下:
在这里插入图片描述
你会发现虽然是match_all,但是响应结果中并不会包含索引库中的所有文档,而是仅仅有10条,这是因为出于安全考虑,elasticSearch设置了默认的查询页数.

1.2 叶子查询

叶子查询的类型也可以做进一步细分,详情大家可以参考官方文档:
https://www.elastic.co/guide/en/elasticsearch/reference/7.12/query-dsl.html

如图:
在这里插入图片描述
这里列举一些常见的,例如:

  • 全文检索查询(Full Text Queries): 利用分词器对用户输入搜索条件先分词,得到词条,然后在利用倒排索引搜索词条,例如:
    • match
    • multi_match
  • 精确查询(Term-level queries): 不对用户输入搜索条件分词,根据字段内容精确值匹配,但是只能查找keyword,数值,日期,boolean类型的字段,比如:
    • ids
    • term
    • range
  • 地理坐标查询: 用于搜索地理位置,搜索方式很多,例如:
    • geo_bounding_box: 按照矩形搜索
    • geo_distance: 按点和半径搜索

1.2.1 全文检索查询

全文检索的种类也很多,详情可以参考官方文档:
https://www.elastic.co/guide/en/elasticsearch/reference/7.12/full-text-queries.html

以全文检索中的match为例,语法如下:

GET /{索引库名}/_search
{"query": {"match": {"字段名": "搜索条件"}}
}

示例:
在这里插入图片描述
match类似的语法还有multi_match,区别在于可以同时对多个字段字段进行搜索,而且多个字段都要满足,语法示例:

GET /{索引库名}/_search
{"query": {"multi_match": {"query": "搜索条件","fields": ["字段1", "字段2"]}}
}

示例:
在这里插入图片描述

1.2.2 精确查询

精确查询,英文是Term-level query,顾名思义,词条级别的查询,也就是说不会对用户输入的搜索条件再分词,而是作为一个词条,与搜索的字段内容精确值匹配,因此推荐查找keyword,数值,日期,boolean类型的字段,例如:

  • id
  • price
  • 城市
  • 地名
  • 人名

等等,作为一个整体才有含义的字段.
详情可以查看官方文档:
https://www.elastic.co/guide/en/elasticsearch/reference/7.12/term-level-queries.html

以term为例,其语法如下:

GET /{索引库名}/_search
{"query": {"term": {"字段名": {"value": "搜索条件"}}}
}

在这里插入图片描述
当输入的搜索条件不是词条,而是短语是,由于不做分词,反而搜索不到:
在这里插入图片描述
再看接下来range查询,语法如下:

GET /{索引库名}/_search
{"query": {"range": {"字段名": {"gte": {最小值},"lte": {最大值}}}}
}

range是范围查询,对于范围筛选的关键字有:

  • gte: 大于等于
  • gt: 大于
  • lte: 小于等于
  • lt: 小于

示例:
在这里插入图片描述

1.3 复合查询

复合查询大致可以分为两类:

  • 第一类: 基于逻辑运算组合叶子查询,实现组合条件,例如
    • bool
  • 第二类: 基于某种算法修改查询时的文档相关性算分,从而改变文档排名,例如:
    • function_score
    • dis_max

其他复合查询以及相关语法可以参考官方文档:
https://www.elastic.co/guide/en/elasticsearch/reference/7.12/compound-queries.html

1.3.1 算分函数查询

当我们利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时按照分值降序排列.
例如我们搜索"手机",结果如下:
在这里插入图片描述
从es5.1开始,采用的相关性打分算法是BM25算法,公式如下:
在这里插入图片描述
基于这套公式,救护可以判断出某个文档与用户搜索的关键字之间的关联度,还是比较准确的,但是,在实际业务需求中,常常会有竞价排名的功能,不是相关度越高排名越靠前,而是基于掏的钱多的排名更加靠前.
例如在百度中搜索java培训,排名靠前的就是广告推广:
在这里插入图片描述
要想人为控制相关性算分,就需要利用elasticsearch中的function sorce查询了.
基本语法:
function socre查询中包含了四部分内容:

  • 原始查询条件: query部分,基于这个条件搜索文档,并且基于BM25算法给文档打分,原始算分.
  • 过滤条件: filter部分,复合该条件的文档才会重新算分.
  • 算分函数: 复合filter条件的文档要根据这个函数做运算,得到的函数算分(function score),有四种函数
    • weight: 函数结果是常量
    • field_value_factor: 以文档中的某个字段值作为函数结果
    • random_socre: 以随机数作为函数结果
    • script_score: 自定义算分函数算法
  • 运算模式: 算分函数的结果,原始查询的相关性算分,两者之间的运算方式,包括:
    • multiply: 相乘
    • replace: 用function socre替换query socre
    • 其他,例如: sum,avg,max,min

function socre的运行流程如下:

  1. 根据原始条件查询搜索文档,并且计算相关性算分,称为原始算分.
  2. 根据过滤条件,过滤文档
  3. 复合过滤条件的文档,基于算分函数运算,得到函数算分.
  4. 原始算分函数算分基于运算模式做运算,得到最终结果,作为相关性算分.

因此,其中的关键点是:

  • 过滤条件: 决定哪些文档的算分被修改
  • 算分函数: 决定函数算分的算法
  • 运算模式: 决定最终算分结果

示例: 给iPhone这个品牌的手机算分提高十倍,分析如下:

  • 过滤条件: 品牌必须为iPhone
  • 算分函数: 常量weight,值为10
  • 算分模式: 相乘multiply

对应代码如下:

GET /hotel/_search
{"query": {"function_score": {"query": {  .... }, // 原始查询,可以是任意条件"functions": [ // 算分函数{"filter": { // 满足的条件,品牌必须是Iphone"term": {"brand": "Iphone"}},"weight": 10 // 算分权重为2}],"boost_mode": "multipy" // 加权模式,求乘积}}
}

1.3.2 bool查询

bool查询,即布尔查询,就是利用逻辑运算来组合一个或者多个子查询子句的组合.
bool查询支持的逻辑运算有:

  • must: 必须匹配每个子查询,类似于"与"
  • should; 选择性匹配子查询,类似"或"
  • must_not: 必须不匹配,不参与算分,类似于"非"
  • filter: 必须匹配,不参与算分(和must的区别).

bool查询语法如下:

GET /items/_search
{"query": {"bool": {"must": [{"match": {"name": "手机"}}],"should": [{"term": {"brand": { "value": "vivo" }}},{"term": {"brand": { "value": "小米" }}}],"must_not": [{"range": {"price": {"gte": 2500}}}],"filter": [{"range": {"price": {"lte": 1000}}}]}}
}

出于性能考虑,与搜索关键字无关的查询尽量采用must_notfilter逻辑运算,避免参与相关性算分.
例如黑马商城的搜索页面:
在这里插入图片描述
其中输入框的搜索条件肯定要参与相关性算分,可以采用match,但是价格范围过滤,品牌过滤,分类过滤尽量采用filter,不要参与相关性算分.
比如,我们要搜索"手机",但是品牌必须是"华为",价格必须是900~1599,那么可以这样写:

GET /items/_search
{"query": {"bool": {"must": [{"match": {"name": "手机"}}],"filter": [{"term": {"brand": { "value": "华为" }}},{"range": {"price": {"gte": 90000, "lt": 159900}}}]}}
}

1.4 排序

elasticSearch默认是根据相关度算分(_socre)来排序,但是也支持自定方式对搜索结果排序.不过分词字段无法排序,能参与排序字段类型有: keyword类型,数值类型,地理坐标类型,日期类型.
详细说明可以参考官方文档:
https://www.elastic.co/guide/en/elasticsearch/reference/7.12/sort-search-results.html
语法说明:

GET /indexName/_search
{"query": {"match_all": {}},"sort": [{"排序字段": {"order": "排序方式asc和desc"}}]
}

示例,我们按照商品价格排序:

GET /items/_search
{"query": {"match_all": {}},"sort": [{"price": {"order": "desc"}}]
}

1.5 分页

elasticsearch默认情况下只返回top10的数据.而如果要查询的更多数据就需要修改分页参数了.

1.5.1 基础分页

elasticSearch中通过修改form,size参数来控制要返回的分页结果:

  • from: 从第几个文档开始
  • size: 总共查询几个文档

类似于MySQL中的limit ?,?,官方文档如下:
官方文档如下:
https://www.elastic.co/guide/en/elasticsearch/reference/7.12/paginate-search-results.html
语法如下:

GET /items/_search
{"query": {"match_all": {}},"from": 0, // 分页开始的位置,默认为0"size": 10,  // 每页文档数量,默认10"sort": [{"price": {"order": "desc"}}]
}

1.5.2 深度分页

elasticSearch的数据一般会采用分片存储,也就是把一个索引中的数据分成N份,存储到不同的节点上,这种存储方式比较有利于数据扩展,但是给分页带来了一些麻烦.
比如一个索引库中有100000条数据,分别存储到4个分片,每个分片25000条数据.现在每页查询10条,查询99页,那么分页查询的条件如下:

GET /items/_search
{"from": 990, // 从第990条开始查询"size": 10, // 每页查询10条"sort": [{"price": "asc"}]
}

从语句来分析,要查询第990-1000名的数据.从数显思路来分析,坑定是将所有数据排序,找出前1000名,截取其中的990-1000的部分,但是问题来了,我们如何才能找到所有数据中的前1000名呢?
要知道每一片的数据都不一样,第一片上的第990-1000,在另一个节点上并不一定依然是990-1000名,所以我们只能在每一个分片上都要找出排名前1000的数据,然后汇总到一起,重新排序,才能找出整个索引库中真正的前1000名,此时截取的990-1000的数据即可.

就像我们高中的时候有普通班,有尖子班,比如有5个班,其中有一个尖子班,我们找全年级前50的时候,肯定不能只挑每个班的前10名,全年级前50肯定是尖子班多一些,所以我们在选人的时候需要对全年级进行排名.在这里插入图片描述

试想一下,加入我们现在要查询的是第999页数据呢,是不是要找地9990-10000的数据,那岂不是要把每个分片中的前10000名的数据都查询出来,汇总到一起,在内存中排序?如果查询的分页深度更深呢,需要一次检索的数据岂不是更多?
由此可知,当查询分页深度较大时,汇总的数据过多,对内存和CPU会产生非常大的压力.
因此elasticSearch会禁止from+ size超过10000的请求.
针对深度分页,elasticSearch提供了两种解决方案:

  • Search after: 分页时需要排序,原理是从上一次的排序开始,查询下一页数据,官方推荐使用的方式.
  • scroll: 原理将排序后的文档id形成快照,保存下来,基于快照做分页,官方已经不推荐使用.

总结:
大多数情况下,我们采用普通分页就是可以了,一般我们采用限制分页深度的方式即可,无需实现深度分页.

1.6 高亮

1.6.1 高亮显示原理

什么是高亮显示呢?
我们在百度,京东搜索的时候,关键字就会变成红色,比较醒目,这就叫高亮显示:
在这里插入图片描述
观察页面源码,你会发现两件事情:

  • 高亮词条都被加上的了<em>标签.
  • <em>标签都添加了红色样式.

css样式肯定是前端实现页面的时候写好的,但是前端编写页面的时候是不知道页面要展示什么数据的,不可能给数据加标签,而服务端实现搜索功能,要是有elasticSearch做分词搜索,要是知道哪些词条需要高亮的.
因此词条的高亮标签肯定是有服务端提供数据的时候已经加上的.

因此实现高亮的思路就是:

  • 用户搜索关键字搜索数据
  • 服务端根据搜索关键字找到elasticSearch搜索,并给搜索结果中的关键字词条添加一个html标签
  • 前端提前给约定好的html标签添加css样式.

1.6.2 实现高亮

事实上elasticSearch已经提供了给搜索关键字加标签的语法,无需我们自己编码.基本语法如下:

GET /{索引库名}/_search
{"query": {"match": {"搜索字段": "搜索关键字"}},"highlight": {"fields": {"高亮字段名称": {"pre_tags": "<em>","post_tags": "</em>"}}}
}

注意:

  • 搜索必须有查询条件,而且是全文检索类型的查询条件,例如match
  • 参与高亮的字段必须是text类型的字段.
  • 默认情况下参与高亮的字段要与搜索字段一致,除非添加 required_field_match=false.

示例:
在这里插入图片描述

1.7 总结

查询的DSL是一个大的json对象,包含下列属性:

  • query: 查询条件
  • from和size: 分页条件
  • sort: 排序条件
  • hightlight: 高亮条件

示例:
在这里插入图片描述

2. RestClient查询

文档的查询依然使用上一节学习的RestHighLevelClient对象,查询的基本步骤如下:

  • 创建request对象,这次是搜索,所以是searchRequest
  • 准备请求参数,也就是查询DSL对应的json参数
  • 发起请求
  • 解析响应,响应对应的结果相对复杂,需要逐层解析

2.1 快速入门

之前说过,由于elasticSearch对外暴露的接口都是restful风格的接口,因此JavaAPI调用就是在发送http请求,而我们核心要做的就是利用Java代码组织请求参数,解析响应结果.
这个参数的格式完全参考DSL查询语句的json结构,因此我们在学习的过程中,会不断的把JavaAPI与DSL语句做对比.

2.2.1 发送请求

首先以match_all查询为例,其DSL和JavaAPI的对比如图:
在这里插入图片描述
代码解读:

  • 第一步,创建SearchRequest对象,指定索引库名
  • 第二部,利用request.source()创建DSL,DSL中可以包含查询,分页,排序,高亮等
    • query(): 代表查询条件,利用QueryBuilders.matchAllQuery()构建一个match_all查询的DSL.
  • 第三步,利用client.search()发送请求,得到响应

这里关键的API有两个,一个是request.source(),它构建的就是DSL中的完整的json参数,其中包含了query、sort、from、size、highlight等所有功能:
在这里插入图片描述
另一个是QueryBuilders,其中包含了我们学习过的各种叶子查询,复合查询等:
在这里插入图片描述

2.1.2 解析响应结果

在发送请求以后,得到了相应的结果SearchResponse,这个类的结构与我们在kibana中看到的相应结果json接口完全一致:

{"took" : 0,"timed_out" : false,"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "heima","_type" : "_doc","_id" : "1","_score" : 1.0,"_source" : {"info" : "Java讲师","name" : "赵云"}}]}
}

因此,我们解析SearchResponse的代码就是在解析这个json结果,对比如下:
在这里插入图片描述
代码解读:
elasticsearch返回的结果是一个json字符串,结构包含:

  • hit: 命中的结果
    • total: 总条数,其中value是具体的总条数值
    • max_score: 所有的结果中得分最高的文档的相关性算分
    • hit: 搜索结果的文档数组,其中的每个文档都是json对象
      • _source: 文档中的原始数据,也是json对象

因此,我们解析响应结果,就是逐层解析json字符串,流程如下:

  • SearchHits: 通过response.getHits()获取,就是json中最外层的hits,代表命中的结果
    • SearchHits#getTotalHits().value: 获取总条数信息
    • SearchHits#getHits(): 获取SearchHit数组,也就是文档数组
      • SearchHit#getSourceAsString(): 获取文档结果中的_source,也就是原始的json文档数据

2.1.3 总结

文档搜索的基本步骤是:

  1. 创建SearchRequest对象
  2. 准备request.source(),也就是DSL.
    • QueryBuilders来构建查询条件
    • 传入request.source()query()方法
  3. 发送请求,得到结果
  4. 解析结果(参考json结果,从外到内,逐层解析)

完整代码如下:

@Test
void testMatchAll() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数request.source().query(QueryBuilders.matchAllQuery());// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}private void handleResponse(SearchResponse response) {SearchHits searchHits = response.getHits();// 1.获取总条数long total = searchHits.getTotalHits().value;System.out.println("共搜索到" + total + "条数据");// 2.遍历结果数组SearchHit[] hits = searchHits.getHits();for (SearchHit hit : hits) {// 3.得到_source,也就是原始json文档String source = hit.getSourceAsString();// 4.反序列化并打印ItemDoc item = JSONUtil.toBean(source, ItemDoc.class);System.out.println(item);}
}

2.2 叶子查询

所有条件都是由QueryBuilders来构建的,叶子查询页不例外,因此整套代码中变化的部分仅仅是query条件构造的方式,其他的不动:

@Test
void testMatch() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数request.source().query(QueryBuilders.matchQuery("name", "脱脂牛奶"));// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}

再比如multi_match查询:

@Test
void testMultiMatch() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数request.source().query(QueryBuilders.multiMatchQuery("脱脂牛奶", "name", "category"));// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}

还有range查询:

@Test
void testRange() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数request.source().query(QueryBuilders.rangeQuery("price").gte(10000).lte(30000));// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}

还有term查询:

@Test
void testTerm() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数request.source().query(QueryBuilders.termQuery("brand", "华为"));// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}

2.3 复合查询

复合查询也是由QueryBuilders构建,我们以bool查询为例,DSL和javaAPI的对比如图:
在这里插入图片描述
完整代码如下:

@Test
void testBool() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数// 2.1.准备bool查询BoolQueryBuilder bool = QueryBuilders.boolQuery();// 2.2.关键字搜索bool.must(QueryBuilders.matchQuery("name", "脱脂牛奶"));// 2.3.品牌过滤bool.filter(QueryBuilders.termQuery("brand", "德亚"));// 2.4.价格过滤bool.filter(QueryBuilders.rangeQuery("price").lte(30000));request.source().query(bool);// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}

2.4 排序和分页

之前说过,requeset.source()就是整个请求json参数,所以排序,分页都是基于这个来设置,其DSL和JavaAPI的对比如下:
在这里插入图片描述
完整的示例代码:

@Test
void testPageAndSort() throws IOException {int pageNo = 1, pageSize = 5;// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数// 2.1.搜索条件参数request.source().query(QueryBuilders.matchQuery("name", "脱脂牛奶"));// 2.2.排序参数request.source().sort("price", SortOrder.ASC);// 2.3.分页参数request.source().from((pageNo - 1) * pageSize).size(pageSize);// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}

2.5 高亮

高亮查询与前面的查询有两点不同:

  • 条件同样是在request.source()中指定,只不过高亮条件要基于HighlightBuilder来构造
  • 高亮相应结果与搜索的文档结果不在一起,需要单独解析

首先来看高亮条件构造,其DSL和JavaAPI的对比如图:
在这里插入图片描述
示例代码如下:

@Test
void testHighlight() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数// 2.1.query条件request.source().query(QueryBuilders.matchQuery("name", "脱脂牛奶"));// 2.2.高亮条件request.source().highlighter(SearchSourceBuilder.highlight().field("name").preTags("<em>").postTags("</em>"));// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}

再来看结果解析,文档解析的部分不变,主要是高亮内容需要单独解析出来,其DSL和JavaAPI的对比如图:
在这里插入图片描述
代码解读:

  • 第3、4步:从结果中获取_source。hit.getSourceAsString(),这部分是非高亮结果,json字符串。还需要反序列为ItemDoc对象
  • 第5步:获取高亮结果。hit.getHighlightFields(),返回值是一个Map,key是高亮字段名称,值是HighlightField对象,代表高亮值
  • 第5.1步:从Map中根据高亮字段名称,获取高亮字段值对象HighlightField
  • 第5.2步:从HighlightField中获取Fragments,并且转为字符串。这部分就是真正的高亮字符串了
  • 最后:用高亮的结果替换ItemDoc中的非高亮结果

完整代码如下:

private void handleResponse(SearchResponse response) {SearchHits searchHits = response.getHits();// 1.获取总条数long total = searchHits.getTotalHits().value;System.out.println("共搜索到" + total + "条数据");// 2.遍历结果数组SearchHit[] hits = searchHits.getHits();for (SearchHit hit : hits) {// 3.得到_source,也就是原始json文档String source = hit.getSourceAsString();// 4.反序列化ItemDoc item = JSONUtil.toBean(source, ItemDoc.class);// 5.获取高亮结果Map<String, HighlightField> hfs = hit.getHighlightFields();if (CollUtils.isNotEmpty(hfs)) {// 5.1.有高亮结果,获取name的高亮结果HighlightField hf = hfs.get("name");if (hf != null) {// 5.2.获取第一个高亮结果片段,就是商品名称的高亮值String hfName = hf.getFragments()[0].string();item.setName(hfName);}}System.out.println(item);}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词