当前位置:   article > 正文

elasticsearch 搜索

elasticsearch 搜索

目录

1、安装

1)下载:

 2、安装/运行

  3)、安装可视化界面

2、java 使用ES

1、项目pom文件

2、配置文件中es的配置编写

3、创建es的配置类

①将配置文件的属性已对象的方式封装

②ES的配置类: 

4、ES的工具类编写

5、ES的工具类使用:

扩展:(推荐的使用方式)


es的相关概念:

倒排序原理:

倒排索引的基本原理是:

将 一个句子、文章进行分词 得到term,创建倒排序索引,以term为key,句子是否包含来确定评分,计算总分进行排序

具体如下:

1. 通过分析网页内容,提取网页中出现的所有词语,并记录每个词语出现在哪些网页中。

2. 将上述信息倒排过来,以词语为主要索引建立索引。每个词语下面都指向包含该词语的网页列表。

3. 当搜索词输入后,搜索引擎通过倒排索引找到包含每个搜索词的网页,然后计算它们的交集,得到最终结果。

例如:举个简单例子:

假设有3个网页,内容如下:

网页1:我喜欢打篮球和足球   文档1
网页2:我喜欢听音乐和看书  文档2
网页3:我喜欢游泳和跑步     文档3

将上述网页内容进行分词,得到的term如下:

我、喜欢、打、篮球、和、足球
我、喜欢、听、音乐、和、看、书
我、喜欢、游泳、和、跑步

构建标准索引如下:

我:网页1,网页2,网页3
喜欢:网页1,网页2,网页3
打:网页1 
篮球:网页1
和:网页1,网页2,网页3
足球:网页1
听:网页2
音乐:网页2 
看:网页2
书:网页2
游泳:网页3
跑步:网页3

倒排索引如下:

我:网页1,网页2,网页3 
喜欢:网页1,网页2,网页3 
打:网页1 
篮球:网页1
足球:网页1 
和:网页1,网页2,网页3
听:网页2
音乐:网页2 
看:网页2
书:网页2
游泳:网页3
跑步:网页3

当用户输入查询“我喜欢音乐”,搜索引擎会在倒排索引中查找:

我:网页1,网页2,网页3 
喜欢:网页1,网页2,网页3 
音乐:网页2由于只有网页2同时包含我、喜欢和音乐这3个词,

所以,搜索引擎会将网页2返回作为查询结果。

以上:

整个列表 称之为  索引

句子(即 文档)被分词器分词后得到的是 term(term是搜索引擎理解网页和查询的基本单位)

当输入“我爱中国”,搜索引擎根据倒排索引,我→网页1,网页2;爱→网页1,网页2;中国→网页2。取交集,得到结果为网页2。所以,倒排索引通过倒转标准索引的结构,使用词语作为主要索引,指向包含每个词语的网页,加速了搜索引擎的查询检索过程,是分布式搜索引擎的基础

1、安装

1)下载:

官方下载地址: Download Elasticsearch | Elastic

我是去历史版本里下载的 7.10.1版本 

 

 2、安装/运行

下载后,解压缩,运行bin目录的:elasticsearch.bat即可运行

运行后看到如下界面:

然后访问: localhost:9200

说明:安装成功! 

(坑:之前作者安装了 但是死活访问不了,后面可能是因为安装了node.js才解决,不确定解决的方法) 

额外的配置:

4.打开 config/elasticsearch.yml  ,末尾添加跨域的配置:         

  1. http.cors.enabled: true
  2. http.cors.allow-origin: "*"

修改后记得重新运行elasticsearch.bat
 

  3)、安装可视化界面

1.安装GitHub elasticsearch-head插件: 下载地址:GitHub - mobz/elasticsearch-head: A web front end for an elastic search cluster

2、安装Node.js:下载地址 Download | Node.js

在window的cmd中执行: 

node -v     查看nodejs是否安装成功 
npm -v      查看npm是否安装成功

cd C:\Users\tzcon\Desktop\es\elasticsearch-head-master          进入head目录下

  1. npm install -g grunt-cli          //grunt是一个很方便的构建工具,可以进行打包压缩、测试、执行等等的工作
  2. npm install

 启动:可视化界面

grunt server

 这时候可以访问:

http://localhost:9100/

使用:

参考:

 (81条消息) Windows环境下安装ES全文搜素引擎与head插件_我的世界没光的博客-CSDN博客

2、java 使用ES

(请参考:扩展:(推荐的使用方式)) 

项目目录结构:

1、项目pom文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.1.4.RELEASE</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.sxw</groupId>
  12. <artifactId>springboot-elasticsearch</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>springboot-elasticsearch</name>
  15. <description>Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. <elasticsearch.version>7.10.1</elasticsearch.version>
  19. </properties>
  20. <dependencies>
  21. <!--使用springboot的 component装配等注解-->
  22. <dependency>
  23. <groupId>org.springframework.boot</groupId>
  24. <artifactId>spring-boot-starter-web</artifactId>
  25. </dependency>
  26. <!--免得写set、get方法-->
  27. <dependency>
  28. <groupId>org.projectlombok</groupId>
  29. <artifactId>lombok</artifactId>
  30. <optional>true</optional>
  31. </dependency>
  32. <!--一会单元测试 java的操作es的函数测试-->
  33. <dependency>
  34. <groupId>org.springframework.boot</groupId>
  35. <artifactId>spring-boot-starter-test</artifactId>
  36. <scope>test</scope>
  37. </dependency>
  38. <!--以下两个都是 es的内容-->
  39. <dependency>
  40. <groupId>org.elasticsearch.client</groupId>
  41. <artifactId>elasticsearch-rest-high-level-client</artifactId>
  42. <version>7.10.1</version>
  43. </dependency>
  44. <dependency>
  45. <groupId>org.elasticsearch</groupId>
  46. <artifactId>elasticsearch</artifactId>
  47. <version>7.10.1</version>
  48. </dependency>
  49. <!--引入IOUtil-->
  50. <dependency>
  51. <groupId>commons-io</groupId>
  52. <artifactId>commons-io</artifactId>
  53. <version>2.3</version>
  54. </dependency>
  55. <!--json字符串的转换-->
  56. <dependency>
  57. <groupId>com.alibaba</groupId>
  58. <artifactId>fastjson</artifactId>
  59. <version>1.2.4</version>
  60. </dependency>
  61. <!--解决配置文件application.yml 的语法不识别-->
  62. <dependency>
  63. <groupId>org.springframework.boot</groupId>
  64. <artifactId>spring-boot-configuration-processor</artifactId>
  65. <optional>true</optional>
  66. </dependency>
  67. </dependencies>
  68. <build>
  69. <plugins>
  70. <plugin>
  71. <groupId>org.springframework.boot</groupId>
  72. <artifactId>spring-boot-maven-plugin</artifactId>
  73. </plugin>
  74. </plugins>
  75. </build>
  76. </project>

2、配置文件中es的配置编写

  1. spring:
  2. rest:
  3. host: 127.0.0.1
  4. port: 9200
  5. protocol: http
  6. username:
  7. password:

3、创建es的配置类

①将配置文件的属性已对象的方式封装

  1. package com.sxw.elasticsearch.config;
  2. import lombok.Data;
  3. import org.springframework.boot.context.properties.ConfigurationProperties;
  4. import org.springframework.stereotype.Component;
  5. @Data
  6. @Component
  7. @ConfigurationProperties(prefix = "spring.rest")
  8. public class RestProperties {
  9. private String host;
  10. private int port;
  11. private String protocol;
  12. private String username;
  13. private String password;
  14. }

②ES的配置类: 

  1. package com.sxw.elasticsearch.config;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.apache.http.HttpHost;
  4. import org.apache.http.impl.nio.reactor.IOReactorConfig;
  5. import org.elasticsearch.client.RestClient;
  6. import org.elasticsearch.client.RestClientBuilder;
  7. import org.elasticsearch.client.RestHighLevelClient;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.beans.factory.annotation.Qualifier;
  10. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  11. import org.springframework.context.annotation.Bean;
  12. import org.springframework.context.annotation.Configuration;
  13. @Slf4j
  14. @Configuration
  15. @EnableConfigurationProperties(RestProperties.class)
  16. public class RestClientConfig {
  17. @Autowired
  18. @Qualifier("restProperties")
  19. private RestProperties properties;
  20. @Bean
  21. public RestHighLevelClient client() {
  22. RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(properties.getHost(), properties.getPort(), properties.getProtocol()));
  23. restClientBuilder.setRequestConfigCallback(builder -> {
  24. // 连接超时(默认为1秒)
  25. builder.setConnectTimeout(5000);
  26. // 套接字超时(默认为30秒)
  27. builder.setSocketTimeout(60000);
  28. return builder;
  29. });
  30. restClientBuilder.setHttpClientConfigCallback(builder -> {
  31. // 线程数
  32. builder.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build());
  33. return builder;
  34. });
  35. return new RestHighLevelClient(restClientBuilder);
  36. }
  37. }

4、ES的工具类编写

摘抄自网络上:亲测可用

  1. package com.sxw.elasticsearch.util;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import lombok.Data;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.apache.commons.io.IOUtils;
  7. import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
  8. import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
  9. import org.elasticsearch.action.bulk.BulkRequest;
  10. import org.elasticsearch.action.bulk.BulkResponse;
  11. import org.elasticsearch.action.delete.DeleteRequest;
  12. import org.elasticsearch.action.delete.DeleteResponse;
  13. import org.elasticsearch.action.get.GetRequest;
  14. import org.elasticsearch.action.get.GetResponse;
  15. import org.elasticsearch.action.index.IndexRequest;
  16. import org.elasticsearch.action.index.IndexResponse;
  17. import org.elasticsearch.action.search.SearchRequest;
  18. import org.elasticsearch.action.search.SearchResponse;
  19. import org.elasticsearch.action.support.master.AcknowledgedResponse;
  20. import org.elasticsearch.action.update.UpdateRequest;
  21. import org.elasticsearch.action.update.UpdateResponse;
  22. import org.elasticsearch.client.RequestOptions;
  23. import org.elasticsearch.client.RestClient;
  24. import org.elasticsearch.client.RestHighLevelClient;
  25. import org.elasticsearch.client.indices.CreateIndexRequest;
  26. import org.elasticsearch.client.indices.CreateIndexResponse;
  27. import org.elasticsearch.client.indices.GetIndexRequest;
  28. import org.elasticsearch.common.Strings;
  29. import org.elasticsearch.common.text.Text;
  30. import org.elasticsearch.common.unit.DistanceUnit;
  31. import org.elasticsearch.common.unit.TimeValue;
  32. import org.elasticsearch.common.xcontent.XContentType;
  33. import org.elasticsearch.index.query.BoolQueryBuilder;
  34. import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
  35. import org.elasticsearch.index.query.QueryBuilder;
  36. import org.elasticsearch.index.query.QueryBuilders;
  37. import org.elasticsearch.index.reindex.BulkByScrollResponse;
  38. import org.elasticsearch.index.reindex.DeleteByQueryRequest;
  39. import org.elasticsearch.index.reindex.UpdateByQueryRequest;
  40. import org.elasticsearch.script.Script;
  41. import org.elasticsearch.script.ScriptType;
  42. import org.elasticsearch.search.SearchHit;
  43. import org.elasticsearch.search.aggregations.AggregationBuilder;
  44. import org.elasticsearch.search.aggregations.Aggregations;
  45. import org.elasticsearch.search.aggregations.metrics.Cardinality;
  46. import org.elasticsearch.search.builder.SearchSourceBuilder;
  47. import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
  48. import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
  49. import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
  50. import org.elasticsearch.search.sort.SortOrder;
  51. import org.springframework.beans.factory.annotation.Autowired;
  52. import org.springframework.core.io.ClassPathResource;
  53. import org.springframework.stereotype.Component;
  54. import org.springframework.util.CollectionUtils;
  55. import org.springframework.util.StringUtils;
  56. import java.io.*;
  57. import java.net.HttpURLConnection;
  58. import java.net.URL;
  59. import java.net.URLConnection;
  60. import java.nio.charset.StandardCharsets;
  61. import java.util.ArrayList;
  62. import java.util.Collections;
  63. import java.util.List;
  64. import java.util.Map;
  65. import java.util.concurrent.TimeUnit;
  66. @Slf4j
  67. @Component
  68. @Data
  69. public class RestClientService {
  70. /**
  71. * ES最大数据限制
  72. */
  73. public static final int MAX_DATA_SIZE = 100;
  74. @Autowired
  75. private RestHighLevelClient restHighLevelClient;
  76. /********************************************创建mapping********************************************/
  77. /**
  78. * 加载文件内容
  79. *
  80. * @param path
  81. * @return
  82. */
  83. public String loadText(String path) {
  84. String textData = null;
  85. try {
  86. ClassPathResource classPathResource = new ClassPathResource(path);
  87. try (InputStream inputStream = classPathResource.getInputStream()) {
  88. textData = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
  89. }
  90. } catch (Exception e) {
  91. log.error("load mappping file error, cause {0}", e);
  92. }
  93. return textData;
  94. }
  95. /**
  96. * 创建mapping映射
  97. *
  98. * @param index
  99. * @param path
  100. * @return
  101. */
  102. public boolean createIndexMapping(String index, String path) {
  103. PutMappingRequest request = new PutMappingRequest(index);
  104. request.source(loadText(path), XContentType.JSON);
  105. try {
  106. AcknowledgedResponse response = restHighLevelClient.indices().putMapping(request, RequestOptions.DEFAULT);
  107. return response.isAcknowledged();
  108. } catch (IOException e) {
  109. log.error("create index mapping error, cause {0}", e);
  110. }
  111. return false;
  112. }
  113. /********************************************索引(创建,删除,存在)********************************************/
  114. /**
  115. * 创建索引,若索引不存在且创建成功,返回true,若同名索引已存在,返回false
  116. *
  117. * @param index 索引名称
  118. * @return
  119. */
  120. public boolean createIndex(String index) {
  121. //创建索引请求
  122. CreateIndexRequest request = new CreateIndexRequest(index);
  123. //执行创建请求IndicesClient,请求后获得响应
  124. try {
  125. CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
  126. return response.isAcknowledged();
  127. } catch (Exception e) {
  128. log.error("create index error, cause {0}", e);
  129. }
  130. return false;
  131. }
  132. /**
  133. * 删除索引,删除成功返回true,删除失败返回false
  134. *
  135. * @param index 索引名称
  136. * @return true/false
  137. */
  138. public boolean deleteIndex(String index) {
  139. if (!existsIndex(index)) {
  140. log.debug("deleteIndex error, cause: {} not exists", index);
  141. return false;
  142. }
  143. DeleteIndexRequest request = new DeleteIndexRequest(index);
  144. try {
  145. AcknowledgedResponse response =restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
  146. return response.isAcknowledged();
  147. } catch (Exception e) {
  148. log.error("delete index error, cause {0}", e);
  149. }
  150. return false;
  151. }
  152. /**
  153. * 判断索引是否存在,若存在返回true,若不存在或出现问题返回false
  154. *
  155. * @param index 索引名称
  156. * @return
  157. */
  158. public boolean existsIndex(String index) {
  159. GetIndexRequest request = new GetIndexRequest(index);
  160. try {
  161. restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
  162. } catch (Exception e) {
  163. log.error("existsIndex error, cause {0}", e);
  164. }
  165. return false;
  166. }
  167. /********************************************文档(创建,更新,删除,存在)********************************************/
  168. /**
  169. * 新增/修改文档信息
  170. *
  171. * @param index 索引名称
  172. * @param id 文档id
  173. * @param data 数据
  174. * @return
  175. */
  176. public boolean createDocument(String index, String id, JSONObject data) {
  177. try {
  178. IndexRequest request = new IndexRequest(index);
  179. if (id != null && id.length() > 0) {
  180. request.id(id);
  181. }
  182. request.source(JSON.toJSONString(data), XContentType.JSON);
  183. IndexResponse response =restHighLevelClient.index(request, RequestOptions.DEFAULT);
  184. String status = response.status().toString();
  185. if ("CREATED".equals(status) || "OK".equals(status)) {
  186. return true;
  187. }
  188. } catch (Exception e) {
  189. log.error("put data error, cause {0}", e);
  190. }
  191. return false;
  192. }
  193. /**
  194. * 批量插入文档,id是随机的
  195. *
  196. * @param index 索引名称
  197. * @param datas 数据的集合
  198. * @return
  199. */
  200. public boolean createDocuments(String index, List<JSONObject> datas) {
  201. try {
  202. BulkRequest bulkRequest = new BulkRequest();
  203. if (!CollectionUtils.isEmpty(datas)) {
  204. for (Object obj : datas) {
  205. bulkRequest.add(new IndexRequest(index).source(JSON.toJSONString(obj), XContentType.JSON));
  206. }
  207. BulkResponse response =restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
  208. log.debug("putDataBulk:{}", response);
  209. if (!response.hasFailures()) {
  210. return true;
  211. }
  212. }
  213. } catch (Exception e) {
  214. log.error("put data bulk error, cause {0}", e);
  215. }
  216. return false;
  217. }
  218. /**
  219. * 更新文档
  220. *
  221. * @param index 索引名称
  222. * @param id 文档id
  223. * @param data 数据
  224. * @return
  225. */
  226. public boolean updateDocumentById(String index, String id, JSONObject data) {
  227. try {
  228. UpdateRequest request = new UpdateRequest(index, id);
  229. request.doc(JSON.toJSONString(data), XContentType.JSON);
  230. UpdateResponse response =restHighLevelClient.update(request, RequestOptions.DEFAULT);
  231. String status = response.status().toString();
  232. if ("OK".equals(status)) {
  233. return true;
  234. }
  235. } catch (Exception e) {
  236. log.error("update data error, cause {0}", e);
  237. }
  238. return false;
  239. }
  240. /**
  241. * 删除文档
  242. *
  243. * @param index 索引名称
  244. * @param id 文档id
  245. * @return
  246. */
  247. public boolean deleteDocument(String index, String id) {
  248. try {
  249. DeleteRequest request = new DeleteRequest(index, id);
  250. DeleteResponse response =restHighLevelClient.delete(request, RequestOptions.DEFAULT);
  251. String status = response.status().toString();
  252. if ("OK".equals(status)) {
  253. return true;
  254. }
  255. } catch (Exception e) {
  256. log.error("delete data error, cause {0}", e);
  257. }
  258. return false;
  259. }
  260. /**
  261. * 批量删除文档
  262. *
  263. * @param index 索引名称
  264. * @param ids 文档id的集合
  265. * @return
  266. */
  267. public boolean deleteDataBulk(String index, List<String> ids) {
  268. BulkRequest request = new BulkRequest();
  269. for (String id : ids) {
  270. request.add(new DeleteRequest().index(index).id(id));
  271. }
  272. try {
  273. BulkResponse response =restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
  274. return !response.hasFailures();
  275. } catch (Exception e) {
  276. log.error("delete data bulk error, cause {0}", e);
  277. }
  278. return false;
  279. }
  280. /**
  281. * 条件删除
  282. *
  283. * @param index 索引名称
  284. * @param queryBuilder 删除条件
  285. * @return
  286. */
  287. public boolean deleteByQuery(String index, QueryBuilder queryBuilder) {
  288. DeleteByQueryRequest request = new DeleteByQueryRequest(index);
  289. request.setRefresh(true);
  290. request.setQuery(queryBuilder);
  291. try {
  292. BulkByScrollResponse response =restHighLevelClient.deleteByQuery(request, RequestOptions.DEFAULT);
  293. return response.getStatus().getDeleted() > 0;
  294. } catch (IOException e) {
  295. log.error("delete by query error, cause {0}", e);
  296. }
  297. return false;
  298. }
  299. /**
  300. * 条件更新
  301. *
  302. * @param index 索引名称
  303. * @param queryBuilder 更新条件
  304. * @return
  305. */
  306. public boolean updateByQuery(String index, QueryBuilder queryBuilder, String script) {
  307. UpdateByQueryRequest request = new UpdateByQueryRequest(index);
  308. request.setConflicts("proceed");
  309. request.setQuery(queryBuilder);
  310. request.setScript(new Script(ScriptType.INLINE, "painless", script, Collections.emptyMap()));
  311. try {
  312. BulkByScrollResponse response =restHighLevelClient.updateByQuery(request, RequestOptions.DEFAULT);
  313. return response.getStatus().getUpdated() > 0;
  314. } catch (IOException e) {
  315. log.error("update by query error, cause {0}", e);
  316. }
  317. return false;
  318. }
  319. /**
  320. * 判断文档是否存在
  321. *
  322. * @param index 索引名称
  323. * @param id 文档id
  324. * @return
  325. */
  326. public boolean existsDocument(String index, String id) {
  327. GetRequest request = new GetRequest(index, id);
  328. try {
  329. GetResponse response =restHighLevelClient.get(request, RequestOptions.DEFAULT);
  330. return response.isExists();
  331. } catch (Exception e) {
  332. log.error("existsData error, cause {0}", e);
  333. }
  334. return false;
  335. }
  336. /********************************************文档(查询)********************************************/
  337. /**
  338. * 条件查询
  339. *
  340. * @param index 索引名称
  341. * @param queryBuilder 查询条件
  342. * @param aggregationBuilder 聚合条件
  343. * @return
  344. */
  345. public SearchResponse query(String index, QueryBuilder queryBuilder, AggregationBuilder aggregationBuilder) {
  346. SearchRequest searchRequest = new SearchRequest(index);
  347. SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
  348. searchSourceBuilder.trackTotalHits(true);
  349. searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
  350. // 查询条件
  351. if (queryBuilder != null) {
  352. searchSourceBuilder.query(queryBuilder);
  353. }
  354. // 聚合条件
  355. if (aggregationBuilder != null) {
  356. searchSourceBuilder.aggregation(aggregationBuilder);
  357. }
  358. searchRequest.source(searchSourceBuilder);
  359. try {
  360. restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
  361. } catch (IOException e) {
  362. log.error("select distinct count error cause: {0}", e);
  363. }
  364. return null;
  365. }
  366. /**
  367. * 查询数量
  368. *
  369. * @param index 索引名称
  370. * @param queryBuilder 查询条件
  371. * @return
  372. */
  373. public Long selectCount(String index, QueryBuilder queryBuilder) {
  374. SearchResponse response = query(index, queryBuilder, null);
  375. if (response == null) {
  376. return 0L;
  377. }
  378. return response.getHits().getTotalHits().value;
  379. }
  380. /**
  381. * 聚合查询-返回统计数值
  382. *
  383. * @param index 索引名称
  384. * @param aggName 聚合名称
  385. * @param queryBuilder 查询条件
  386. * @param aggregationBuilder 聚合条件
  387. * @return 统计值
  388. */
  389. public Long selectCount(String index, String aggName, QueryBuilder queryBuilder, AggregationBuilder aggregationBuilder) {
  390. SearchResponse response = query(index, queryBuilder, aggregationBuilder);
  391. if (response == null) {
  392. return 0L;
  393. }
  394. Aggregations aggregations = response.getAggregations();
  395. // 根据聚合名称获取统计值
  396. Cardinality cardinality = aggregations.get(aggName);
  397. return cardinality.getValue();
  398. }
  399. /**
  400. * 批量新增
  401. *
  402. * @paramrestHighLevelClient
  403. * @param indexName
  404. * @param list
  405. */
  406. public static void multiAdd(RestHighLevelClient restHighLevelClient, String indexName, List<Object> list) {
  407. BulkRequest request = new BulkRequest();
  408. request.timeout("10s");
  409. //批量请求,批量更新,删除都差不多!!!不设置id就会自动生成随机id,演示为批量插入
  410. for (int i = 0; i < list.size(); i++) {
  411. request.add(new IndexRequest(indexName)
  412. .id("" + (i + 1))
  413. .source(JSON.toJSONString(list.get(i)), XContentType.JSON));
  414. }
  415. try {
  416. BulkResponse response =restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
  417. log.info("=====> multiAdd():" + JSONObject.toJSONString(response));
  418. } catch (IOException e) {
  419. log.error("=====> multiAdd()出错:" + e.getMessage());
  420. }
  421. }
  422. /**
  423. * 通过ID获取数据
  424. * @param index 索引,类似数据库
  425. * @param id 数据ID
  426. * @param fields 需要显示的字段,逗号分隔(缺省为全部字段)
  427. * @return
  428. */
  429. public Map<String,Object> searchDataById(String index, String id, String fields) throws IOException {
  430. GetRequest request = new GetRequest();
  431. request.index(index);
  432. request.id(id);
  433. if (!StringUtils.isEmpty(fields)){
  434. //只查询特定字段。如果需要查询所有字段则不设置该项。
  435. request.fetchSourceContext(new FetchSourceContext(true,fields.split(","), Strings.EMPTY_ARRAY));
  436. }
  437. GetResponse response =restHighLevelClient.get(request, RequestOptions.DEFAULT);
  438. return response.getSource();
  439. }
  440. /**
  441. * 根据经纬度查询范围查找location 经纬度字段,distance 距离中心范围KM,lat lon 圆心经纬度
  442. * @param index
  443. * @param longitude
  444. * @param latitude
  445. * @param distance
  446. * @return
  447. */
  448. public SearchResponse geoDistanceQuery(String index,Float longitude, Float latitude,String distance) throws IOException {
  449. if(longitude == null || latitude == null){
  450. return null;
  451. }
  452. //拼接条件
  453. BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
  454. // QueryBuilder isdeleteBuilder = QueryBuilders.termQuery("isdelete", false);
  455. // 以某点为中心,搜索指定范围
  456. GeoDistanceQueryBuilder distanceQueryBuilder = new GeoDistanceQueryBuilder("location");
  457. distanceQueryBuilder.point(latitude, longitude);
  458. //查询单位:km
  459. distanceQueryBuilder.distance(distance, DistanceUnit.KILOMETERS);
  460. boolQueryBuilder.filter(distanceQueryBuilder);
  461. // boolQueryBuilder.must(isdeleteBuilder);
  462. SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
  463. searchSourceBuilder.query(boolQueryBuilder);
  464. SearchRequest searchRequest = new SearchRequest(index);
  465. searchRequest.source(searchSourceBuilder);
  466. SearchResponse searchResponse =restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);
  467. return searchResponse;
  468. }
  469. /**
  470. * 获取低水平客户端
  471. * @return
  472. */
  473. public RestClient getLowLevelClient() {
  474. return restHighLevelClient.getLowLevelClient();
  475. }
  476. /**
  477. * 高亮结果集 特殊处理
  478. * map转对象 JSONObject.parseObject(JSONObject.toJSONString(map), Content.class)
  479. * @param searchResponse
  480. * @param highlightField
  481. */
  482. private List<Map<String, Object>> setSearchResponse(SearchResponse searchResponse, String highlightField) {
  483. //解析结果
  484. ArrayList<Map<String,Object>> list = new ArrayList<>();
  485. for (SearchHit hit : searchResponse.getHits().getHits()) {
  486. Map<String, HighlightField> high = hit.getHighlightFields();
  487. HighlightField title = high.get(highlightField);
  488. Map<String, Object> sourceAsMap = hit.getSourceAsMap();//原来的结果
  489. //解析高亮字段,将原来的字段换为高亮字段
  490. if (title!=null){
  491. Text[] texts = title.fragments();
  492. String nTitle="";
  493. for (Text text : texts) {
  494. nTitle+=text;
  495. }
  496. //替换
  497. sourceAsMap.put(highlightField,nTitle);
  498. }
  499. list.add(sourceAsMap);
  500. }
  501. return list;
  502. }
  503. /**
  504. * 查询并分页
  505. * @param index 索引名称
  506. * @param query 查询条件
  507. * @param size 文档大小限制
  508. * @param fields 需要显示的字段,逗号分隔(缺省为全部字段)
  509. * @param sortField 排序字段
  510. * @param highlightField 高亮字段
  511. * @return
  512. */
  513. public List<Map<String, Object>> searchListData(String index,
  514. SearchSourceBuilder query,
  515. Integer from,
  516. Integer size,
  517. String fields,
  518. String sortField,
  519. String highlightField) throws IOException {
  520. SearchRequest request = new SearchRequest(index);
  521. SearchSourceBuilder builder = query;
  522. if (!StringUtils.isEmpty(fields)){
  523. //只查询特定字段。如果需要查询所有字段则不设置该项。
  524. builder.fetchSource(new FetchSourceContext(true,fields.split(","), Strings.EMPTY_ARRAY));
  525. }
  526. from = from <= 0 ? 0 : from*size;
  527. //设置确定结果要从哪个索引开始搜索的from选项,默认为0
  528. builder.from(from);
  529. builder.size(size);
  530. if (!StringUtils.isEmpty(sortField)){
  531. //排序字段,注意如果proposal_no是text类型会默认带有keyword性质,需要拼接.keyword
  532. builder.sort(sortField+".keyword", SortOrder.ASC);
  533. }
  534. //高亮
  535. HighlightBuilder highlight = new HighlightBuilder();
  536. highlight.field(highlightField);
  537. //关闭多个高亮
  538. highlight.requireFieldMatch(false);
  539. highlight.preTags("<span style='color:red'>");
  540. highlight.postTags("</span>");
  541. builder.highlighter(highlight);
  542. //不返回源数据。只有条数之类的数据。
  543. // builder.fetchSource(false);
  544. request.source(builder);
  545. SearchResponse response =restHighLevelClient.search(request, RequestOptions.DEFAULT);
  546. log.info("result:"+response.getHits().getTotalHits());
  547. System.out.println(JSON.toJSONString(response.getHits()));
  548. if (response.status().getStatus() == 200) {
  549. // 解析对象
  550. return setSearchResponse(response, highlightField);
  551. }
  552. return null;
  553. }
  554. }

5、ES的工具类使用:

  1. package com.sxw.elasticsearch.test;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.sxw.elasticsearch.MyBaseTest;
  5. import com.sxw.elasticsearch.model.Product;
  6. import com.sxw.elasticsearch.util.RestClientService;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.apache.lucene.search.join.ScoreMode;
  9. import org.elasticsearch.action.index.IndexRequest;
  10. import org.elasticsearch.client.RestHighLevelClient;
  11. import org.elasticsearch.common.xcontent.XContentType;
  12. import org.elasticsearch.index.query.QueryBuilders;
  13. import org.elasticsearch.search.builder.SearchSourceBuilder;
  14. import org.junit.Test;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.data.domain.PageRequest;
  17. import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
  18. import org.springframework.data.elasticsearch.core.SearchHit;
  19. import org.springframework.data.elasticsearch.core.SearchHits;
  20. import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
  21. import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
  22. import java.io.IOException;
  23. import java.util.*;
  24. /**
  25. * @author wangjianwei
  26. * * @date 2022/4/19
  27. */
  28. @Slf4j
  29. public class eeee extends MyBaseTest {
  30. @Autowired
  31. RestHighLevelClient client;
  32. @Test
  33. public void aa() throws IOException {
  34. // Create the "products" index
  35. IndexRequest request = new IndexRequest("posts");
  36. request.id("1");
  37. String jsonString = "{" +
  38. "\"user\":\"kimchy\"," +
  39. "\"postDate\":\"2013-01-30\"," +
  40. "\"message\":\"trying out Elasticsearch\"" +
  41. "}";
  42. request.source(jsonString, XContentType.JSON);
  43. System.out.println();
  44. }
  45. @Autowired
  46. RestClientService restClientService;
  47. @Test
  48. public void createIndex() {
  49. boolean blog2 = restClientService.createIndex("blog3");
  50. System.out.println();
  51. }
  52. //如果没有blog1索引,则会自动创建
  53. @Test
  54. public void createDocument() {
  55. JSONObject data= JSON.parseObject("{\"age\":\"10\",\"name\":\"李四\",\"address\":{\"area1\":\"萧山区\",\"area2\":\"杭州市\"} }");
  56. boolean blog1 = restClientService.createDocument("blog1","1",data);
  57. System.out.println(blog1);
  58. }
  59. //批量插入
  60. @Test
  61. public void createDocuments() {
  62. JSONObject data1= JSON.parseObject("{\"age\":\"10\",\"name\":\"李四11\",\"address\":{\"area1\":\"萧山区11\",\"area2\":\"杭州市\"} }");
  63. JSONObject data2= JSON.parseObject("{\"age\":\"10\",\"name\":\"李四22\",\"address\":{\"area1\":\"萧山区22\",\"area2\":\"杭州市\"} }");
  64. ArrayList<JSONObject> arrayList = new ArrayList<>();
  65. arrayList.add(data1);
  66. arrayList.add(data2);
  67. boolean blog1 = restClientService.createDocuments("blog1",arrayList);
  68. System.out.println(blog1);
  69. }
  70. @Test
  71. public void existsIndex() {
  72. boolean blog2 = restClientService.existsIndex("blog3");
  73. System.out.println(blog2);
  74. }
  75. @Test
  76. public void deleteIndex() {
  77. boolean flag = restClientService.deleteIndex("blog3");
  78. System.out.println(flag);
  79. }
  80. @Test
  81. public void deleteDocumentById() {
  82. boolean flag = restClientService.deleteDocument("blog1","1");
  83. System.out.println(flag);
  84. }
  85. @Test
  86. public void updateDocument() {
  87. JSONObject data= JSON.parseObject("{\"age\":\"99\",\"name\":\"李四7\",\"address\":{\"area1\":\"萧山区\",\"area2\":\"杭州市1\"} }");
  88. boolean flag = restClientService.updateDocumentById("blog1","1",data);
  89. System.out.println(flag);
  90. }
  91. @Test
  92. public void searchDataById() throws IOException {
  93. Map<String, Object> stringObjectMap = restClientService.searchDataById("blog1", "1", "");
  94. Map<String, Object> stringObjectMap1 = restClientService.searchDataById("blog1", "1", "address");
  95. System.out.println(stringObjectMap);
  96. }
  97. //复合分页的查询
  98. @Test
  99. public void searchListData1() throws IOException {
  100. SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
  101. RestHighLevelClient restHighLevelClient = restClientService.getRestHighLevelClient();
  102. restHighLevelClient.search()
  103. List<Map<String, Object>> maps = restClientService.searchListData("patpat-products", searchSourceBuilder, 0, 2, "", "", "");
  104. String datas = JSON.toJSONString(maps);
  105. System.out.println(datas);
  106. }
  107. }

扩展:(推荐的使用方式)

事实上,springboot的自动配置已经有了elasticsearch的配置,我们只需要告诉springboot的es地址、用户、密码、端口就可以了如:

配置好这一行后,spring容器中自动给我们注入了restHighLevelClient  的对象,如果我们想要像其他数据库的常规用途:XXXTemplate。这时Maven引入: 

  1. <!--如果想要使用ElasticsearchRestTemplate 那就引入此依赖没否则-->
  2. <dependency>
  3. <groupId>org.springframework.data</groupId>
  4. <artifactId>spring-data-elasticsearch</artifactId>
  5. <version>4.0.9.RELEASE</version>
  6. <scope>compile</scope>
  7. <exclusions>
  8. <exclusion>
  9. <artifactId>transport</artifactId>
  10. <groupId>org.elasticsearch.client</groupId>
  11. </exclusion>
  12. </exclusions>
  13. </dependency>

 源码理解:

使用:

  1. @Autowired
  2. // ElasticsearchRestTemplate 类中有 RestHighLevelClient作为属性,我们配置 RestClientConfig 后 会在spring容器中注入了 该属性,
  3. ElasticsearchRestTemplate elasticsearchRestTemplate;
  4. //复合分页的查询
  5. @Test
  6. public void searchListData() throws IOException {
  7. //模拟参数
  8. ArrayList<Integer> list = new ArrayList<>();
  9. list.add(1);
  10. list.add(2);
  11. //该条件构造器 各种条件的拼接 类似于mybatis-plus 中的 queryWrapper
  12. NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
  13. builder.withPageable(PageRequest.of(0, Integer.parseInt(String.valueOf(1000))));
  14. builder.withQuery(QueryBuilders.boolQuery()
  15. .must(QueryBuilders.termsQuery("product_id", list))
  16. .must(QueryBuilders.nestedQuery(
  17. "sale_status",
  18. QueryBuilders.boolQuery()
  19. .must(QueryBuilders.termQuery("sale_status.store_id", 30000))
  20. .must(QueryBuilders.termQuery("sale_status.status", 11)),
  21. ScoreMode.None)));
  22. NativeSearchQuery build = builder.build();
  23. //上面条件器构造好了, 现在要去查哪个 索引呢? 其实spring注解有简便的方法,在返回的解析类中进行标记,如下:语句
  24. SearchHits<Product> it = elasticsearchRestTemplate.search(build, Product.class);
  25. System.out.println("");
  26. // //使用elasticsearchRestTemplate查询索引aa的结构
  27. Map<String, Object> index_name = elasticsearchRestTemplate.indexOps(IndexCoordinates.of("aa")).getMapping();
  28. }

其中: Product为:

 debug结果:

XXQueryBuilder的“翻译”:

es的查询技巧 类比sql: 

sql转es的在线工具:

在线工具:SQL转ElasticSearch DSL - 潇洒哥和黑大帅

好文参考:

(下文中可能由于版本不同 部分语法不同,但基本变化不大)

1、快速上手-聚合分析 | MRCODE-BOOK 

2、bool 组合多个 filter 搜索 | MRCODE-BOOK

扩展:一些语句和区分

  1. 外层的bool查询包含了几个should查询,这意味着满足任何一个内层的bool查询即可匹配。
    1. bool
    2. |__should
    3. |__should
    4. |__should
    5. 3个should只要有一个匹配到就算
  2. 如果bool查询同时包含mustfilter子句和should子句,那么即使should子句的条件不被满足,文档也有可能被查出来,只要它们满足mustfilter中的条件。在这种情况下,should子句的作用是提高满足其条件的文档的相关性得分(_score),而不是作为硬性的匹配条件
    1. bool
    2. |__should (此刻should不是必须匹配了)
    3. |__must
    4. |__must
    5. |__filter
  3. term和filter的区别
    特性term查询filter子句
    目的用于精确匹配字段的值用于过滤文档,确保它们符合某些标准
    评分计算并使用相关性得分(_score)进行排序不计算相关性得分,不影响排序
    性能相对较慢,因为需要计算得分相对较快,因为不计算得分且结果可以被缓存
    缓存通常不缓存查询结果可以缓存结果,提高重复查询的性能
    使用场景当你需要根据精确值进行搜索且关心文档的排名时使用当你只需要过滤文档且不关心文档的排名时使用
    示例{
        "term": {
            "status": "active"
        }
    }
    {
        "bool": {
            "filter": {
                "term": {
                    "status": "active"
                }
            }
        }
    }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/842302
推荐阅读
相关标签
  

闽ICP备14008679号