当前位置: 首页 > news >正文

Elasticsearch实战(一):Springboot实现Elasticsearch统一检索功能

文章目录

  • 系列文章索引
  • 一、准备工作
    • 1、搭建docker环境
    • 2、安装es+kibana
    • 3、es安装ik分词器
      • (1)下载安装
      • (2)测试
    • 4、Springboot
      • (1)引包
      • (2)客户端公共方法
      • (3)公共实体类
      • (4)公共工具类
    • 5、数据准备
      • (1)添加映射
      • (2)批量添加数据
  • 二、全文检索
    • 1、代码
    • 2、为什么二次处理高亮
  • 三、结构化搜索与过滤
    • 1、概述
    • 2、结构化过滤(Filter DSL)
      • (1)term 过滤
      • (2)terms 过滤
      • (3)range 过滤
      • (4)exists 和 missing 过滤
      • (5)bool 过滤
    • 3、结构化查询(Query DSL)
      • (1)bool 查询
      • (2)bool嵌套查询
      • (3)match_all 查询
      • (4)match 查询
      • (5)multi_match 查询
      • (6)match_phrase
      • (7)phrase_prefix 查询
      • (8)regexp查询
      • (9)过滤查询
    • 4、Java实现通用结构化查询API
      • (1)Java实现
      • (2)排序方式一
      • (3)排序方式二

系列文章索引

Elasticsearch实战(一):Springboot实现Elasticsearch统一检索功能
Elasticsearch实战(二):Springboot实现Elasticsearch自动汉字、拼音补全,Springboot实现自动拼写纠错
Elasticsearch实战(三):Springboot实现Elasticsearch搜索推荐
Elasticsearch实战(四):Springboot实现Elasticsearch指标聚合与下钻分析
Elasticsearch实战(五):Springboot实现Elasticsearch电商平台日志埋点与搜索热词

一、准备工作

1、搭建docker环境

快速搭建centos7虚拟机——使用virtualbox+vagrant
centos7安装与卸载docker-简单而详细无坑

2、安装es+kibana

docker安装elasticSearch+kibana

注意,我们本次使用的是elasticSearch7.4.0 + kibana7.4.0

3、es安装ik分词器

(1)下载安装

下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
找到对应版本的分词器:https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.0/elasticsearch-analysis-ik-7.4.0.zip

# 将分词器插件拷贝到es容器
docker cp /root/elasticsearch-analysis-ik-7.4.0.zip 7f1456dff26d:/usr/share/elasticsearch/plugins
# 进入容器
docker exec -it cb5bffb16ac5 /bin/bash
# 安装zip命令
yum install -y unzip zip
# 创建目录
mkdir /usr/share/elasticsearch/plugins/elasticsearch-analysis-ik-7.4.0
# 解压
unzip -d /usr/share/elasticsearch/plugins/elasticsearch-analysis-ik-7.4.0 /usr/share/elasticsearch/plugins/elasticsearch-analysis-ik-7.4.0.zip
rm -f /usr/share/elasticsearch/plugins/elasticsearch-analysis-ik-7.4.0.zip
# 重启es
docker restart cb5bffb16ac5
# 查看日志
docker logs cb5bffb16ac5

(2)测试

GET _analyze
{"analyzer" : "ik_smart","text" : "小米全面屏手机奥利给"
}GET _analyze
{"analyzer" : "ik_max_word","text" : "小米全面屏手机奥利给"
}

我们发现,执行结果,并不识别“全面屏” 、 “奥利给”。我们需要自定义分词。

cd /mydata/elasticsearch/plugins/elasticsearch-analysis-ik-7.4.0/config
vi IKAnalyzer.cfg.xml#修改内容:
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">my.dic</entry># 自定义分词
vi my.dic
# 内容:
奥利给
全面屏# 重启es
docker restart cb5bffb16ac5

此时,奥利给 、 全面屏 这两个网络词语,就支持了。

4、Springboot

(1)引包

<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.4.0</version>
</dependency>

(2)客户端公共方法

private final static String cluster_host = "192.168.56.10";
private final static Integer eNode3_port = 9200;
/*** 超时时间设为5分钟*/
private static final int TIME_OUT = 5 * 60 * 1000;private static final RestHighLevelClient client = highLevelClient();private static RestClientBuilder restClientBuilder() {return RestClient.builder( // 可以传多个作为集群new HttpHost(cluster_host, eNode3_port, "http"));}/*** 获取客户端*/
public static RestHighLevelClient highLevelClient() {RestClientBuilder restClientBuilder = restClientBuilder();restClientBuilder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {@Overridepublic RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {return requestConfigBuilder.setSocketTimeout(TIME_OUT);}});return new RestHighLevelClient(restClientBuilder);
}

(3)公共实体类

//如果加该注解的字段为null,那么就不序列化
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CommonEntity implements Serializable {//页码private int pageNumber;//每页数据条数private int pageSize;//索引名称private String indexName;//高亮列private String highlight;//排序 DESC  ASCprivate String sortOrder;//排序列private String sortField;//自动补全建议列private String suggestFileld;//自动补全建议值private String suggestValue;//自动补全返回个数private Integer suggestCount;//动态查询参数封装(重要)Map<String, Object> map;//批量增加listprivate List<Map<String, Object>> list;// ... get  set
}
public class CommonMap<K,V> extends HashMap<K,V> {public CommonMap putData(K key, V value) {super.put(key, value);return this;}
}

(4)公共工具类

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchModule;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;/*** @Class: SearchTools 查询服务工具类*/
public class SearchTools {/** @Description: 高亮前端显示组装,SearchResponse传递引用* 为什么二次处理高亮?* 原因:被设置的高亮列,es自动放到了highlight属性中;这个属性渲染了高亮的着色* 数据传输的时候,我们需要将它取出来* 覆盖到我们的_source中* @Method: setHighResult* @Param: [searchResponse, commonEntity]* @Update:* @since: 1.0.0* @Return: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>***/public static void setHighResultForCleintUI(SearchResponse searchResponse, String highlightField) {if (StringUtils.isNoneEmpty(highlightField)) {for (SearchHit hit : searchResponse.getHits()) {//获取高亮字段mapMap<String, HighlightField> highlightFields = hit.getHighlightFields();//获取到具体的高亮列HighlightField highlightFieldName = highlightFields.get(highlightField);//getSourceAsMap拿到具体的数据Map<String, Object> source = hit.getSourceAsMap();if (highlightFieldName != null) {//获取渲染后的文本Text[] fragments = highlightFieldName.fragments();String name = "";for (Text text : fragments) {name += text;}source.put(highlightField, name);   //高亮字段替换掉原本的内容}}}}/** @Description: 获取高亮构建器* @Method:* @Param:* @Update:* @since: 1.0.0* @Return:**/public static HighlightBuilder getHighlightBuilder(String highlightField) {// 设置高亮,使用默认的highlighter高亮器,默认em斜体HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器highlightBuilder.field(highlightField);      //高亮查询字段highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为falsehighlightBuilder.preTags("<span style= " +"color:red;font-weight:bold;font-size:15px;" +">");   //高亮设置highlightBuilder.postTags("</span>");//下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等highlightBuilder.fragmentSize(800000); //最大高亮分片数highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段return highlightBuilder;}/** @Description: 获取排序  DESC  ASC 前端不区分大小写,默认返回DESC* @Method: getSortOrder* @Param: [sortOrder]* @Update:* @since: 1.0.0* @Return: org.elasticsearch.search.sort.SortOrder**/public static SortOrder getSortOrder(String sortOrder) {SortOrder so = null;sortOrder = StringUtils.isEmpty(sortOrder) ? "" : sortOrder.toLowerCase();switch (sortOrder) {case "desc":so = SortOrder.DESC;break;case "asc":so = SortOrder.ASC;break;default:so = SortOrder.DESC;break;}return so;}/** @Description: MAP转数组* @Method: mapToObjectGropu* @Param: [data]* @Update:* @since: 1.0.0* @Return: java.lang.Object[]**/public static Object[] mapToObjectGroup(Map<String, Object> data) {List<Object> args = new ArrayList<Object>();if (data != null) {data.forEach((key, value) -> {args.add(key);args.add(value);});}return args.toArray();}/** @Description: 根据客户端传来的查询参数(标准的DSL语句)构建XContentParser* @Method: getXContentParser* @Param: []* @Update:* @since: 1.0.0* @Return: org.elasticsearch.common.xcontent.XContentParser**/public static XContentParser getXContentParser(CommonEntity commonEntity) throws IOException {//构建SearchModule对象置 ,通过构造器注册解析器、建议器、排序等SearchModule searchModule = new SearchModule(Settings.EMPTY, false, Collections.emptyList());//获取注册成功的注册解析器、建议器、排序NamedXContentRegistry registry = new NamedXContentRegistry(searchModule.getNamedXContents());//将前端传来的DSL参数通过解析解解析XContentParser parser = XContentFactory.xContent(XContentType.JSON).createParser(registry, LoggingDeprecationHandler.INSTANCE, JSONObject.toJSONString(commonEntity.getMap()));return parser;}/** @Description: 将查询出来的数据放到本地局部线程变量中* @Method: setResponseThreadLocal* @Param: [response]* @Update:* @since: 1.0.0* @Return: void**/public static void setResponseThreadLocal(SearchResponse response) {//查询出来的数据SearchHit[] sh = response.getHits().getHits();//定义list用来接收所有Resource下面的结果集List<JSONObject> list = new ArrayList<JSONObject>();if (sh != null) {for (SearchHit hit : sh) {list.add(JSONObject.parseObject(hit.getSourceAsString()));}//将数据放入到本地线程ResponseThreadLocal.set(list);}}}
/*** @Description: 使用线程本地局部变量处理结果集*/
public class ResponseThreadLocal {private static final ThreadLocal<List<JSONObject>> threadLocal = new ThreadLocal<List<JSONObject>>();/** @Description: 通过本地线程局部变量获取结果集* @Method: getList* @Param: []* @Update:* @since: 1.0.0* @Return: java.util.List<com.alibaba.fastjson.JSONObject>**/public static List<JSONObject> get() {return threadLocal.get();}/** @Description:* @Method: 将统计后的数据集放入到当前线程* @Param: [list]* @Update:* @since: 1.0.0* @Return: void**/public static void set(final List<JSONObject> list) {threadLocal.set(list);}/** @Description:* @Method: 清空当前线程本地局部变量值;否则内存泄露* @Param: []* @Update:* @since: 1.0.0* @Return: void**/public static void clear() {threadLocal.set(null);}}

5、数据准备

(1)添加映射

PUT product
{"settings": {"number_of_shards": 1,"number_of_replicas": 1},"mappings": {"properties": {"name": {"type": "text"},"price": {"type": "double"} }}
}

或者使用代码:

/** @Description: 新增索引+setting+映射+自定义分词器pinyin* setting可以为空(自定义分词器pinyin在setting中)* 映射可以为空* @Method: addIndexAndMapping* @Param: [commonEntity]* @Return: boolean**/
public boolean addIndexAndMapping(CommonEntity commonEntity) throws Exception {//设置setting的mapMap<String, Object> settingMap = new HashMap<String, Object>();//创建索引请求CreateIndexRequest request = new CreateIndexRequest(commonEntity.getIndexName());//获取前端参数Map<String, Object> map = commonEntity.getMap();//循环外层的settings和mappingfor (Map.Entry<String, Object> entry : map.entrySet()) {if ("settings".equals(entry.getKey())) {if (entry.getValue() instanceof Map && ((Map) entry.getValue()).size() > 0) {request.settings((Map<String, Object>) entry.getValue());}}if ("mapping".equals(entry.getKey())) {if (entry.getValue() instanceof Map && ((Map) entry.getValue()).size() > 0) {request.mapping((Map<String, Object>) entry.getValue());}}}//创建索引操作客户端IndicesClient indices = client.indices();//创建响应对象CreateIndexResponse response = indices.create(request, RequestOptions.DEFAULT);//得到响应结果return response.isAcknowledged();
}

(2)批量添加数据

/** @Description: 批量新增文档,可自动创建索引、自动创建映射* @Method: bulkAddDoc* @Param: [indexName, map]**/
public static RestStatus bulkAddDoc(CommonEntity commonEntity) throws Exception {//通过索引构建批量请求对象BulkRequest bulkRequest = new BulkRequest(commonEntity.getIndexName());//循环前台list文档数据for (int i = 0; i < commonEntity.getList().size(); i++) {bulkRequest.add(new IndexRequest().source(XContentType.JSON, SearchTools.mapToObjectGroup(commonEntity.getList().get(i))));}//执行批量新增BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);return bulkResponse.status();
}public static void main(String[] args) throws Exception {// 批量插入CommonEntity commonEntity = new CommonEntity();commonEntity.setIndexName("product"); // 索引名List<Map<String, Object>> list = new ArrayList<>();commonEntity.setList(list);list.add(new CommonMap<String, Object>().putData("name", "小米(MI)10手机全面屏").putData("price", 2233.8));list.add(new CommonMap<String, Object>().putData("name", "小米(MI)11手机划超酷炫").putData("price", 13123));list.add(new CommonMap<String, Object>().putData("name", "小米(MI)电脑大da屏").putData("price", 213));list.add(new CommonMap<String, Object>().putData("name", "华为手机全面屏大").putData("price", 342));list.add(new CommonMap<String, Object>().putData("name", "华为手机大屏大").putData("price", 1234));list.add(new CommonMap<String, Object>().putData("name", "华为电脑全面屏大奥利给").putData("price", 345));list.add(new CommonMap<String, Object>().putData("name", "华为平板电脑全面屏大奥利给").putData("price", 1234));list.add(new CommonMap<String, Object>().putData("name", "荣耀小米手机").putData("price", 45234));list.add(new CommonMap<String, Object>().putData("name", "手机平板全面屏").putData("price", 4532));bulkAddDoc(commonEntity);
}

查询一下,发现有九条数据了:

GET product/_search

二、全文检索

1、代码

/** @Description: 全文检索* 使用matchQuery在执行查询时,搜索的词会被分词器分词* @Method: searchMatch* @Param: [indexName, key, value]* >>>>>>>>>>>>编写思路简短总结>>>>>>>>>>>>>* >>>>>>>1、构建远程查询* >>>>>>>2、构建查询请求* >>>>>>>3、构建查询条件* >>>>>>>4、设置高亮* >>>>>>>5、设置分页* >>>>>>>   加入SearchRequest* >>>>>>>6、处理高亮**/
public static SearchResponse matchQuery(CommonEntity commonEntity) throws Exception {//构建查询响应SearchResponse response = null;//构建查询请求用来完成和搜索文档,聚合,建议等相关的任何操作同时也提供了各种方式来完成对查询结果的高亮操作。SearchRequest searchRequest = new SearchRequest(commonEntity.getIndexName());//构建DSL请求体;trackTotalHits如果不设置true,查询数据最大值还是10000SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().trackTotalHits(true);//获取前端的查询条件(Map查询条件)getClientConditions(commonEntity, searchSourceBuilder);//高亮设置searchSourceBuilder.highlighter(SearchTools.getHighlightBuilder(commonEntity.getHighlight()));//前端页码int pageNumber = commonEntity.getPageNumber();//前端每页数量int pageSize = commonEntity.getPageSize();//计算查询的下标,从0开始int dest = (pageNumber - 1) * pageSize;searchSourceBuilder.from(dest);//每页数量searchSourceBuilder.size(pageSize);//查询条件对象放入请求对象中searchRequest.source(searchSourceBuilder);//方法执行开始时间long startTime = System.currentTimeMillis();System.out.println("开始Elasticsearch查询...");//执行远程查询,使用RequestOptions.DEFAULT用来构建一个默认缓冲区限制为100MB(源码为DEFAULT_BUFFER_LIMIT = 100 * 1024 * 1024),和header为空、WarningsHandler为空//的参数选项response = client.search(searchRequest, RequestOptions.DEFAULT);//计算远程查询耗时System.out.println("结束Elasticsearch查询总耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");//处理高亮SearchTools.setHighResultForCleintUI(response, commonEntity.getHighlight());return response;}/** @Description: 获取前端的查询条件* @Method: getClientConditions* @Param: [commonEntity, searchSourceBuilder]**/
private static void getClientConditions(CommonEntity commonEntity, SearchSourceBuilder searchSourceBuilder) {//循环前端的查询条件for (Map.Entry<String, Object> m : commonEntity.getMap().entrySet()) {if (StringUtils.isNotEmpty(m.getKey()) && m.getValue() != null) {String key = m.getKey();String value = String.valueOf(m.getValue());//构造请求体中“query”:{}部分的内容 ,QueryBuilders静态工厂类,方便构造queryBuilder//将搜索词分词,再与目标查询字段进行匹配,若分词中的任意一个词与目标字段匹配上,则可查询到。searchSourceBuilder.query(QueryBuilders.matchQuery(key, value));System.out.println(("search for the keyword:" + value));}}
}
public static void main(String[] args) throws Exception {// 全文检索CommonEntity queryEntity = new CommonEntity();queryEntity.setPageNumber(1);// 第一页queryEntity.setPageSize(5); // 一页条数queryEntity.setIndexName("product"); // 索引名queryEntity.setHighlight("name"); // 高亮字段queryEntity.setMap(new CommonMap<>().putData("name", "华为全面屏")); // 要查询的字段 + 内容SearchResponse searchResponse = matchQuery(queryEntity);long aSize = searchResponse.getHits().getTotalHits().value;System.out.println(("数据总数量为>>>" + aSize));long cSize = searchResponse.getHits().getHits().length;System.out.println(("本次获取数据量为>>>" + cSize));System.out.println("内容为>>>" + JSON.toJSONString(searchResponse.getHits().getHits()));System.out.println("全部内容>>>" + JSON.toJSON(searchResponse));
}

2、为什么二次处理高亮

原因:被设置的高亮列,es自动放到了highlight属性中;这个属性渲染了高亮的着色
数据传输的时候,我们需要将它取出来
覆盖到我们的_source中

三、结构化搜索与过滤

1、概述

实现查询价格在【2000-3000】并且是【京东物流】并且评论数【从大到小进行排序】的商品,filter也常和range范围查询一起结合使用,range范围可供组合的选项。

注意!被查询的字段类型是必须是keyword,这样字段在索引时不会进行分词。如果类型为text,字段值在索引时会分词,这样反而查不到结果了。

GET product/_search
{"query": {"bool": {"must": [{"term": {"storetype": "自营"}},{"term": {"twolevel": "手机"}}],"filter": {"range": {"price": {"gte": 2000,"lte": 3000}}}}},"sort": [{"evalcount": {"order": "desc"}}]
}

结构化查询(Query DSL)
query的时候,会先比较查询条件,然后计算分值,最后返回文档结果
结构化过滤(Filter DSL)
过滤器,对查询结果进行缓存,不会计算相关度,避免计算分值,执行速度非常快

2、结构化过滤(Filter DSL)

(1)term 过滤

term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型),相当于sql age=26

{ "term": { "age": 26 }}
{ "term": { "date": "2014-09-01" }}

(2)terms 过滤

terms 允许指定多个匹配条件。如果某个字段指定了多个值,那么文档需要一起去做匹配。
相当于sql: age in

{"terms": {"age": [26, 27, 28]}}

(3)range 过滤

range 过滤允许我们按照指定范围查找一批数据:

{"range": {"price": {"gte": 2000,"lte": 3000}}
}

gt : 大于
lt : 小于
gte : 大于等于
lte :小于等于
相等于sql between

(4)exists 和 missing 过滤

exists 和 missing 过滤可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的IS_NULL条件

{"exists": {"field": "title"}
}

(5)bool 过滤

用来合并多个过滤条件查询结果的布尔逻辑:
must:多个查询条件的完全匹配,相当于 and。
must_not: 多个查询条件的相反匹配,相当于 not;
should:至少有一个查询条件匹配,相当于 or;
相当于sql and 和or

{"bool": {"must": {"term": {"folder": "inbox"}},"must_not": {"term": {"tag": "spam"}},"should": [{"term": {"starred": true}},{"term": {"unread": true}}]}
}

3、结构化查询(Query DSL)

(1)bool 查询

bool 查询与 bool 过滤相似,用于合并多个查询子句。不同的是,bool 过滤可以直接给出是否匹配成功, 而bool 查询要计算每一个查询子句的 _score

{"bool": {"must": {"match": {"title": "how to make millions"}},"must_not": {"match": {"tag": "spam"}},"should": [{"match": {"tag": "starred"}},{"range": {"date": {"gte": "2014-01-01"}}}]}
}

(2)bool嵌套查询

{"bool": {"should": [{"term": {"productID": "KDKE-B-9947-#kL5"}},{"bool": {"must": [{"term": {"productID": "JODL-X-1937-#pV7"}},{"term": {"price": 30}}]}}]}
}

(3)match_all 查询

使用match_all 可以查询到所有文档,是没有查询条件下的默认语句。

{"match_all": {}
}

(4)match 查询

match查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。
如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析match一下查询字符

{"match": {"tweet": "About Search"}
}

(5)multi_match 查询

multi_match查询允许你做match查询的基础上同时搜索多个字段

{"multi_match": {"query": "full text search","fields": [ "title", "body" ]}
}

(6)match_phrase

短语查询,full text search 是一个词组,意味着三个词的位置是连续且有顺序

{"match_phrase": {"title": "full text search",}
}

设置slop词组间隔

{"match_phrase": {"title": {"query": "full text search","slop":1}}
}

(7)phrase_prefix 查询

与词组中最后一个词条进行前缀匹配。

{
"query": {"match_phrase_prefix": {"title": {"query": "全面屏"}}
},
"from":0,
"size":5
}

(8)regexp查询

通配符查询

{"query": {"regexp": {"title": "W[0-9].+"}}
}

(9)过滤查询

查询语句和过滤语句可以放在各自的上下文中,filtered已弃用,用bool代替。

{"query": {"bool": {"must": {"match": {"text": "quick brown fox"}},"filter": {"term": {"status": "published"}}}},"from": 0, // 从0开始"size": 10, // 显示条数"sort": {"publish_date": {"order": "desc"}}
}

4、Java实现通用结构化查询API

(1)Java实现

/** @Description:结构化搜索* @Method: termQuery* @Param: [commonEntity]* @Update:* @since: 1.0.0* @Return: org.elasticsearch.action.search.SearchResponse* >>>>>>>>>>>>编写思路简短总结>>>>>>>>>>>>>* 1、构建远程查询* 2、定义响应* 3、定义查询请求* 3、定义查询构建器* 4、定义解析器--构建器解析* 5、定义高亮* 6、定义分页* 7、定义排序*    加入到SearchRequest* 8、高亮渲染*/
public static SearchResponse termQuery(CommonEntity commonEntity) throws Exception {//构建查询响应SearchResponse response = null;//构建查询请求用来完成和搜索文档,聚合,建议等相关的任何操作同时也提供了各种方式来完成对查询结果的高亮操作。SearchRequest searchRequest = new SearchRequest(commonEntity.getIndexName());//构建DSL请求体trackTotalHits如果不设置true,查询数据最大值还是10000SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().trackTotalHits(true);//将前端的dsl查询转化为XContentParserXContentParser parser = SearchTools.getXContentParser(commonEntity);//将parser解析成功查询APIsearchSourceBuilder.parseXContent(parser);//高亮设置searchSourceBuilder.highlighter(SearchTools.getHighlightBuilder(commonEntity.getHighlight()));//前端页码int pageNumber = commonEntity.getPageNumber();//前端每页数量int pageSize = commonEntity.getPageSize();//计算查询的下标int dest = (pageNumber - 1) * pageSize;searchSourceBuilder.from(dest);//每页数量searchSourceBuilder.size(pageSize);//排序sort(commonEntity, searchSourceBuilder);//查询条件对象放入请求对象中searchRequest.source(searchSourceBuilder);//方法执行开始时间long startTime = System.currentTimeMillis();System.out.println("开始Elasticsearch查询...");//执行远程查询response = client.search(searchRequest, RequestOptions.DEFAULT);//计算远程查询耗时System.out.println("结束Elasticsearch查询总耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");//处理高亮SearchTools.setHighResultForCleintUI(response, commonEntity.getHighlight());return response;
}/** @Description: 排序* @Method: sort* @Param: [commonEntity, searchSourceBuilder]*/
private static void sort(CommonEntity commonEntity, SearchSourceBuilder searchSourceBuilder) {String sortField = commonEntity.getSortField();if (StringUtils.isNotEmpty(sortField)) {//排序,获取前端的order by子句,不区分大小写,参数为空则默认descSortOrder sortOrder = SearchTools.getSortOrder(commonEntity.getSortOrder());//执行排序searchSourceBuilder.sort(new FieldSortBuilder(commonEntity.getSortField()).order(sortOrder));}
}public static void main(String[] args) throws Exception {// 结构化查询CommonEntity queryEntity = new CommonEntity();SearchResponse result = termQuery(queryEntity);//查询数量除以每页数量  等于合计分页数量long aSize = result.getHits().getTotalHits().value;System.out.println(("总数据量:" + aSize + "条"));int cSize = result.getHits().getHits().length;System.out.println(("当前获取数据:" + cSize + "条"));//通过类型推断自动装箱(多个参数取交集)System.out.println(result.getHits().getHits()); // 结果
}

(2)排序方式一

{"pageNumber": 1,"pageSize": 1,"indexName": "product","sortField": "evalcount","sortOrder": "","highlight": "name","map": {"query": {"bool": {"must": [{"term": {"storetype": "自营"}},{"term": {"twolevel": "手机"}}],"filter": {"range": {"price": {"gte": 2000,"lte": 3000}}}}}}
}

pageNumber:页码
pageSize:每页显示条数
indexName:不可以为空,查询的索引名称
sortField:排序列,可以为空
sortOrder:可以为空,默认DESC,排序规则【DESC/ASC】
highlight:高亮字段(注意:平台只接受被查询的字段名称)
map:里面的参数为动态DSL参数;可以随意增加(需符合ES规范)系统可自动解析

(3)排序方式二

{"pageNumber": 1,"pageSize": 1,"indexName": "product_list_info","sortField": "","sortOrder": "","highlight": "productname","map": {"query": {"bool": {"must": [{"term": {"storetype": "自营"}},{"term": {"twolevel": "手机"}}],"filter": {"range": {"price": {"gte": 2000,"lte": 3000}}}}},"sort": [{"evalcount": {"order": "desc"}}]}
}

相关文章:

Elasticsearch实战(一):Springboot实现Elasticsearch统一检索功能

文章目录 系列文章索引一、准备工作1、搭建docker环境2、安装eskibana3、es安装ik分词器&#xff08;1&#xff09;下载安装&#xff08;2&#xff09;测试 4、Springboot&#xff08;1&#xff09;引包&#xff08;2&#xff09;客户端公共方法&#xff08;3&#xff09;公共实…...

更改计算机睡眠时间

控制面板–>系统和安全–>电源选项下的更改计算机睡眠时间 如果关闭显示器时间小于使计算机进入睡眠状态时间&#xff0c;时间先到达关闭显示器时间&#xff0c;显示器关闭&#xff0c;这时电脑还在正常工作状态。如果此时敲击键盘显示器出现画面&#xff0c;无需输入密…...

Matplotlib数据可视化(一)

目录 1.Matplotlib简介 2.Matplotlib绘图基础 2.1 创建画布与子图 2.2 添加画布属性 2.3 绘图的保存与显示 1.Matplotlib简介 Matplotlib是一个用于绘制数据可视化图表的Python库。它提供了广泛的功能和灵活性&#xff0c;可以创建各种类型的图表&#xff0c;包括折线图、…...

LLM提示词工程和提示词工程师Prompting and prompt engineering

你输入模型的文本被称为提示&#xff0c;生成文本的行为被称为推断&#xff0c;输出文本被称为完成。用于提示的文本或可用的内存的全部量被称为上下文窗口。尽管这里的示例显示模型表现良好&#xff0c;但你经常会遇到模型在第一次尝试时无法产生你想要的结果的情况。你可能需…...

Python开发环境(Visual Studio Code、Anaconda、PyInstaller、Enigma Virtual Box)

Python开发环境 [Anaconda、PyInstaller、Enigma Virtual Box] AnacondaAnaconda安装搭建Python环境Anaconda命令 Visual Studio CodeVisual Studio Code中Python设置Visual Studio Code中使用Qt Designer Python打包发布.exe可执行文件PyinstallerEnigma Virtual Box Anaconda…...

Unreal Engine 测试总结

Android 项目打包应选择哪种纹理格式&#xff1f;打包模式区别&#xff1f; 根据官网文档介绍&#xff0c;建议使用 ETC2&#xff1a;所有OpenGL 3.x 类型的设备都支持&#xff0c;并且支持alpha压缩 打包模式包括&#xff1a;内部测试阶段的开发模式&#xff0c;对外发布的发行…...

Air780EG —— 合宙4G定位解决方案

定位模式&#xff1a; 外部单片机控制模式(常见于AT固件客户)&#xff1a; 开机 -> 搜星 -> 定位成功 -> 上报 -> 关机 780E自行控制模式(常见于二次开发客户&#xff0c;AT用户也可以使用): 开机 -> 搜星 -> 定位成功 -> 模块休眠&#xff0c;关闭GP…...

【算法刷题之数组篇(2)】

目录 1.leetcode-35. 搜索插入位置&#xff08;简单&#xff09;2.leetcode-74. 搜索二维矩阵&#xff08;中等&#xff09;3.leetcode-73. 矩阵置零&#xff08;中等&#xff09;4.leetcode-56. 合并区间&#xff08;中等&#xff09;5.leetcode-54. 螺旋矩阵&#xff08;中等…...

chromedriver.exe 的所有版本下载地址

Chrome for Testing availability 上面的网址是V115 v116.... 以上的。 CNPM Binaries Mirror 上面这个是V115版本以下的。 这个文章没有任何实际价值&#xff0c;记录的原因是因为突然发现过去的py无法运行&#xff0c;原因是chrome浏览器偷偷升级到V115&#xff0c;于是找…...

C++ 网络编程项目fastDFS分布式文件系统(四)-fastCGI项目相关技术以及linux搜狗输入法相关问题。

目录 1. Nginx作为web服务器处理请求 2. http协议复习 Get方式提交数据 Post方式提交数据 3. fastCGI 3.1 CGI 3.2 fastCGI 3.3 fastCGI和spawn-fcgi安装 1. 安装fastCGI 2. 安装spawn-fcgi 3.4 nginx && fastcgi 4其他知识点 1. fastCGI环境变量 - fas…...

【HarmonyOS】服务卡片 API6 JSUI跳转不同页面

【引言】 “JS卡片支持为组件设置action&#xff0c;包括router事件和message事件&#xff0c;其中router事件用于应用跳。若设置router事件&#xff0c;则action属性值为"router"&#xff1b;abilityName为卡片提供方应用的跳转目标Ability名&#xff1b;params中的…...

【linux】debian10安装vim

debian10.0上用apt vim安装vim提示依赖的版本冲突。后来发现是软件源没有添加更新源buster-updates。 以下是问答。 问&#xff1a;debian10怎么安装vim? 答&#xff1a; 在 Debian 10 系统上安装 Vim 的方法很简单,主要有以下两种: 1. 使用 apt 命令安装 bash sudo apt u…...

文件同步工具rsync

文章目录 作用特性安装命令服务端启动增加安全认证及免密登录 实时推送源服务器配置结合inotify实现实时推送 参数详解 学些过程中遇到的问题 作用 rsync是linux系统下的数据镜像备份工具。使用快速增量备份工具Remote Sync可以远程同步&#xff0c;支持本地复制&#xff0c;或…...

【嵌入式开发 Linux 常用命令系列 12 -- linux 下 log 输出重定向 详细介绍 】

文章目录 Linux 输出重定向使用背景Linux 重定向使用介绍 上篇文章&#xff1a;嵌入式开发 Linux 常用命令系列 11 – linux 下 任务与CPU绑定命令 taskset 详细介绍 Linux 输出重定向使用背景 在Linux中&#xff0c;输入和输出重定向是非常常见的操作&#xff0c;它们可以用…...

gin中关于参数注入问题

关于参数注入的问题 如果在开发中一旦发小参数没有按照既定的要求注入到结构体的话&#xff0c;这个时候就一定要看请求方式什么&#xff1f;如果是post请求、 前端—post—json{id:1,pageSize:10,page:1}———————————- 参数注入方法&#xff1a;ShouldBindJSON p…...

记录首次面试2023-08-18

人生第一次面试&#xff0c;大概一个小时左右。没有问我C的&#xff0c;上来一个数据库事务&#xff0c;虽然没有复习&#xff0c;但是还是能够记住一些&#xff0c;主要问的一些事务的隔离级别&#xff0c;以及都有什么作用&#xff0c;我是举例回答的&#xff0c;客户端A和客…...

【Apollo学习笔记】——规划模块TASK之LANE_CHANGE_DECIDER

文章目录 前言LANE_CHANGE_DECIDER功能简介LANE_CHANGE_DECIDER相关配置LANE_CHANGE_DECIDER总体流程LANE_CHANGE_DECIDER相关子函数PrioritizeChangeLaneUpdateStatusIsClearToChangeLaneHysteresisFilter 参考 前言 在Apollo星火计划学习笔记——Apollo路径规划算法原理与实…...

rabbitmq的死信队列

目录 成为死信的条件 消息TTL过期 队列达到最大长度 消息被拒 延迟队列 延迟队列使用场景 消息设置 TTL 队列设置 TTL 两者区别 producer 将消息投递到 broker 或者直接到 queue 里了&#xff0c; consumer 从 queue 取出消息 进行消费&#xff0c;但某些时候由…...

利用网络对拷工具进行系统安装与恢复

各学校计算机机房经常批量安装操作系统和应用软件。实现对批量计算机的安 装&#xff0c;应用较多的是使用 Symantec 的 ghost 企业版。但笔者采用的是网络还原精灵 &#xff08;Net Recovery Genius&#xff09;软件附带的网络对拷 Ncp.com 工具&#xff0c;利用它能够轻松实…...

opencv-python使用鼠标点击图片显示该点坐标和像素值IPM逆透视变换车道线二值化处理

OpenCV的鼠标操作 实现获取像素点的功能主要基于OpenCV的内置函数cv2.setMouseCallback()&#xff0c;即鼠标事件回调 setMouseCallback(winname, onMouse,userdata0) winname: 接收鼠标事件的窗口名称 onMouse: 处理鼠标事件的回调函数指针 userdata: 传给回调函数的用户数据…...

AIGC绘画:kaggle部署stable diffusion项目绘画

文章目录 kaggle介绍项目部署edit my copy链接显示 结果展示 kaggle介绍 Kaggle成立于2010年&#xff0c;是一个进行数据发掘和预测竞赛的在线平台。从公司的角度来讲&#xff0c;可以提供一些数据&#xff0c;进而提出一个实际需要解决的问题&#xff1b;从参赛者的角度来讲&…...

微服务概述-7

Shiro 框架 Shiro 是一个用于 Java 应用程序的安全框架。它提供了身份验证、授权、加密和会话管理等功能&#xff0c;可以帮助开发人员构建安全可靠的应用程序。 Java 中针对权限管理常见的有 2 个著名的框架&#xff1a;spring security 和 shiro shiro 基本概念 credentia…...

十二、Linux如何修改文件/文件夹所属用户or用户组?chown命令

目录 1、基础语法 2、修改目标用户&#xff1a; 3、修改用户组&#xff1a; 4、使用-R命令&#xff0c;并同时修改用户/用户组 1、基础语法 chown [-R] [目标用户][:][目标用户组] 被修改文件/文件夹 &#xff08;1&#xff09;选项-R&#xff1a;同chmod&#xff0c;对文…...

企业百家号蓝V认证后,百度营销基木鱼落地页如何嵌入百家号中

首先搭建百度营销基木鱼落地页 在我们的百度营销后台&#xff0c;点击基木鱼跳转至百度营销基木鱼页面&#xff0c;在我的站点位置&#xff0c;可以创建H5站点&#xff0c;PC站点等&#xff0c;创建完成后可以点击复制基木鱼落地页的链接。 注意事项 1、企业百家号需要进行…...

Redis缓存读写策略(三种)数据结构(5+3)

Redis缓存读写策略&#xff08;三种&#xff09; Cache Aside Pattern&#xff08;旁路缓存模式&#xff09; Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式&#xff0c;比较适合读请求比较多的场景。 写&#xff1a; 先更新 db然后直接删除 cache 。 读 : …...

计算机竞赛 Yolov安全帽佩戴检测 危险区域进入检测 - 深度学习 opencv

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; Yolov安全帽佩戴检测 危险区域进入检测 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&am…...

使用python向窗口发送鼠标点击命令

今天遇到一个问题。公司让用电脑在网页上看个视频。网页有个判断&#xff1a;一段时间没有鼠标活动&#xff0c;视频就会暂停。于是就想&#xff0c;能否隔一段时间就模拟鼠标点击一下视频暂停&#xff0c;再点一下继续播放。省得它自己停止播放。这样我就可以让网页窗口在后台…...

C++11并发与多线程笔记(6) unique_lock(类模板)

C11并发与多线程笔记&#xff08;6&#xff09; unique_lock&#xff08;类模板&#xff09; 1、unique_lock取代lock_guard2、unique_lock的第二个参数2.1 std::adopt_lock&#xff1a;2.2 std::try_to_lock&#xff1a;2.3 std::defer_lock&#xff1a; 3、unique_lock的成员…...

计算机网络——OSI与TCP/IP各层的结构与功能,都有哪些协议?

文章目录 一 OSI与TCP/IP各层的结构与功能,都有哪些协议?1.1 应用层1.2 运输层1.3 网络层1.4 数据链路层1.5 物理层1.6 总结一下 二 ⭐TCP 三次握手和四次挥手(面试常客)2.1 TCP 三次握手漫画图解2.2 为什么要三次握手⭐2.3 第2次握手传回了ACK&#xff0c;为什么还要传回SYN&…...

Win7 x86 家庭版SP1 配置 Python 开发环境

1 Win7 下载地址 来源于 MSDN, 我告诉你 - 做一个安静的工具站 ed2k://|file|cn_windows_7_home_basic_with_sp1_x86_dvd_u_676500.iso|2653276160|843E7A78F2126FAC726CF5342710082D|/ 2 Python 版本选择 Python 3.7.9 Python Release Python 3.7.9 | Python.org 3 Pychar…...