当前位置:   article > 正文

ES操作通用类_es updateresponse

es updateresponse

EsTemplate

  1. @Slf4j
  2. @Component
  3. public class EsTemplate {
  4. @Autowired
  5. private RestHighLevelClient client;
  6. private static final String TIMESTAMP = "timestamp";
  7. /**
  8. * 创建索引(默认分片数为5和副本数为1)
  9. *
  10. * @param indexName
  11. * @param esMapTypeClass
  12. * @throws IOException
  13. */
  14. public boolean createIndex(String indexName, Class<? extends IESMappingType> esMapTypeClass) throws IOException {
  15. if (checkIndexExists(indexName)) {
  16. log.error("\"index={}\"索引已经存在!", indexName);
  17. return false;
  18. }
  19. CreateIndexRequest request = new CreateIndexRequest(indexName);
  20. XContentBuilder builder = buildXContentBuilder(indexName, esMapTypeClass);
  21. request.mapping(esMapTypeClass.getSimpleName(), builder);
  22. CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
  23. // 指示是否所有节点都已确认请求
  24. boolean acknowledged = response.isAcknowledged();
  25. // 指示是否在超时之前为索引中的每个分片启动了必需的分片副本数
  26. boolean shardsAcknowledged = response.isShardsAcknowledged();
  27. if (acknowledged || shardsAcknowledged) {
  28. log.info("创建索引成功!索引名称为{}", indexName);
  29. return true;
  30. }
  31. log.error("创建索引失败");
  32. return false;
  33. }
  34. /**
  35. * 创建索引
  36. *
  37. * @param index
  38. * @throws IOException
  39. */
  40. public boolean createIndex(String index) throws IOException {
  41. if (checkIndexExists(index)) {
  42. log.error("\"index={}\"索引已存在!", index);
  43. return false;
  44. }
  45. CreateIndexRequest request = new CreateIndexRequest(index);
  46. CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
  47. boolean acknowledged = response.isAcknowledged();
  48. boolean shardsAcknowledged = response.isShardsAcknowledged();
  49. if (acknowledged || shardsAcknowledged) {
  50. log.info("创建索引成功!索引名称为{}", index);
  51. return true;
  52. } else {
  53. log.error("创建索引失败");
  54. return false;
  55. }
  56. }
  57. /**
  58. * 创建索引(传入参数:分片数、副本数)
  59. *
  60. * @param indexName
  61. * @param shards
  62. * @param replicas
  63. * @throws IOException
  64. */
  65. public boolean createIndex(String indexName, int shards, int replicas) throws IOException {
  66. if (checkIndexExists(indexName)) {
  67. log.error("\"index={}\"索引已存在!", indexName);
  68. return false;
  69. }
  70. Settings.Builder builder = Settings.builder().put("index.number_of_shards", shards).put("index.number_of_replicas", replicas);
  71. CreateIndexRequest request = new CreateIndexRequest(indexName).settings(builder);
  72. // request.mapping(TYPE, generateBuilder());
  73. CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
  74. if (response.isAcknowledged() || response.isShardsAcknowledged()) {
  75. log.info("创建索引成功!索引名称为{}", indexName);
  76. return true;
  77. } else {
  78. log.error("创建索引失败");
  79. return false;
  80. }
  81. }
  82. /**
  83. * 删除索引
  84. *
  85. * @param indexName
  86. * @throws IOException
  87. */
  88. public Boolean deleteIndex(String indexName) throws IOException {
  89. try {
  90. AcknowledgedResponse response = client.indices().delete(new DeleteIndexRequest(indexName), RequestOptions.DEFAULT);
  91. if (response.isAcknowledged()) {
  92. log.info("{} 索引删除成功!", indexName);
  93. return true;
  94. }
  95. } catch (ElasticsearchException ex) {
  96. if (ex.status() == RestStatus.NOT_FOUND) {
  97. log.error("{} 索引名不存在", indexName);
  98. return false;
  99. }
  100. log.error("删除失败!");
  101. }
  102. return false;
  103. }
  104. /**
  105. * 判断索引是否存在
  106. *
  107. * @param indexName
  108. * @return
  109. * @throws IOException
  110. */
  111. public boolean checkIndexExists(String indexName) {
  112. GetIndexRequest request = new GetIndexRequest().indices(indexName);
  113. try {
  114. return client.indices().exists(request, RequestOptions.DEFAULT);
  115. } catch (IOException e) {
  116. log.error("判断索引是否存在,操作异常!");
  117. }
  118. return false;
  119. }
  120. /**
  121. * 开启索引
  122. *
  123. * @param indexName
  124. * @throws IOException
  125. */
  126. public void openIndex(String indexName) throws IOException {
  127. if (!checkIndexExists(indexName)) {
  128. log.error("索引不存在!");
  129. return;
  130. }
  131. OpenIndexRequest request = new OpenIndexRequest(indexName);
  132. OpenIndexResponse response = client.indices().open(request, RequestOptions.DEFAULT);
  133. if (response.isAcknowledged() || response.isShardsAcknowledged()) {
  134. log.info("{} 索引开启成功!", indexName);
  135. }
  136. }
  137. /**
  138. * 关闭索引
  139. *
  140. * @param indexName
  141. * @throws IOException
  142. */
  143. public void closeIndex(String indexName) throws IOException {
  144. if (!checkIndexExists(indexName)) {
  145. log.error("索引不存在!");
  146. return;
  147. }
  148. CloseIndexRequest request = new CloseIndexRequest(indexName);
  149. AcknowledgedResponse response = client.indices().close(request, RequestOptions.DEFAULT);
  150. if (response.isAcknowledged()) {
  151. log.info("{} 索引已关闭!", indexName);
  152. }
  153. }
  154. /**
  155. * 查找文档
  156. *
  157. * @param index
  158. * @param type
  159. * @param id
  160. * @return
  161. * @throws IOException
  162. */
  163. public Map<String, Object> getDocument(String index, String type, String id) throws IOException {
  164. Map<String, Object> resultMap = new HashMap<>();
  165. GetRequest request = new GetRequest(index, type, id);
  166. // 实时(否)
  167. request.realtime(false);
  168. // 检索之前执行刷新(是)
  169. request.refresh(true);
  170. GetResponse response = null;
  171. try {
  172. response = client.get(request, RequestOptions.DEFAULT);
  173. } catch (ElasticsearchException e) {
  174. if (e.status() == RestStatus.NOT_FOUND) {
  175. log.error("文档未找到,请检查参数!");
  176. }
  177. if (e.status() == RestStatus.CONFLICT) {
  178. log.error("版本冲突!");
  179. }
  180. log.error("查找失败!");
  181. }
  182. if (Objects.nonNull(response)) {
  183. if (response.isExists()) { // 文档存在
  184. resultMap = response.getSourceAsMap();
  185. } else {
  186. // 处理未找到文档的方案。 请注意,虽然返回的响应具有404状态代码,但仍返回有效的GetResponse而不是抛出异常。
  187. // 此时此类响应不持有任何源文档,并且其isExists方法返回false。
  188. log.error("文档不存在!");
  189. }
  190. }
  191. return resultMap;
  192. }
  193. /**
  194. * 判断文档是否存在
  195. * @param
  196. * @return true:存在 false:不存在
  197. * @author hucm
  198. * @since 2021/5/31
  199. */
  200. public boolean existDoc(String index, String type, String id) throws IOException {
  201. GetRequest request = new GetRequest(index, type,id);
  202. // 不需要获取source内容
  203. request.fetchSourceContext(new FetchSourceContext(false));
  204. return client.exists(request, RequestOptions.DEFAULT);
  205. }
  206. /**
  207. * 删除文档
  208. *
  209. * @param indexName
  210. * @param typeName
  211. * @param docId
  212. * @throws IOException
  213. */
  214. public void deleteDocument(String indexName, String typeName, String docId) throws IOException {
  215. DeleteRequest request = new DeleteRequest(indexName, typeName, docId);
  216. DeleteResponse response = null;
  217. try {
  218. response = client.delete(request, RequestOptions.DEFAULT);
  219. } catch (ElasticsearchException e) {
  220. if (e.status() == RestStatus.CONFLICT) {
  221. log.error("版本冲突!");
  222. }
  223. log.error("删除失败!");
  224. }
  225. if (Objects.nonNull(response)) {
  226. if (response.getResult() == DocWriteResponse.Result.NOT_FOUND) {
  227. log.error("不存在该文档,请检查参数!");
  228. }
  229. log.info("文档已删除!");
  230. ReplicationResponse.ShardInfo shardInfo = response.getShardInfo();
  231. if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
  232. log.error("部分分片副本未处理");
  233. }
  234. if (shardInfo.getFailed() > 0) {
  235. for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
  236. String reason = failure.reason();
  237. log.error("失败原因:{}", reason);
  238. }
  239. }
  240. }
  241. }
  242. /**
  243. * 通过一个脚本语句(如:"ctx._source.posttime=\"2018-09-18\"")更新文档
  244. * 针对单个字段更新或object类型字段更新
  245. * @param index
  246. * @param type
  247. * @param id
  248. * @param script
  249. */
  250. public void updateDocByScript(String index, String type, String id, String script) throws IOException {
  251. Script inline = new Script(script);
  252. UpdateRequest request = new UpdateRequest(index, type, id).script(inline);
  253. try {
  254. UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
  255. if (response.getResult() == DocWriteResponse.Result.UPDATED) {
  256. //log.info("文档更新成功!");
  257. } else if (response.getResult() == DocWriteResponse.Result.DELETED) {
  258. log.error("\"index={},type={},id={}\"的文档已被删除,无法更新!", response.getIndex(), response.getType(), response.getId());
  259. } else if (response.getResult() == DocWriteResponse.Result.NOOP) {
  260. log.error("操作没有被执行!");
  261. }
  262. ReplicationResponse.ShardInfo shardInfo = response.getShardInfo();
  263. if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
  264. log.error("部分分片副本未处理");
  265. }
  266. if (shardInfo.getFailed() > 0) {
  267. for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
  268. String reason = failure.reason();
  269. log.error("未处理原因:{}", reason);
  270. }
  271. }
  272. } catch (ElasticsearchException e) {
  273. if (e.status() == RestStatus.NOT_FOUND) {
  274. log.error("不存在这个文档,请检查参数!");
  275. } else if (e.status() == RestStatus.CONFLICT) {
  276. log.error("版本冲突异常!");
  277. }
  278. log.error("更新失败!:{},脚本:{},id:{}",e.getMessage(),script,id);
  279. }
  280. }
  281. /**
  282. * 通过一个脚本语句(针对于object和nested数据类型字段更新)更新文档
  283. * @param index
  284. * @param type
  285. * @param id
  286. * @param script
  287. * @param params
  288. * @throws IOException
  289. */
  290. public void updateDocByScript(String index, String type, String id, String script,Map<String, Object> params) throws IOException {
  291. Script inline = new Script(ScriptType.INLINE,Script.DEFAULT_SCRIPT_LANG,script,params);
  292. UpdateRequest request = new UpdateRequest(index, type, id).script(inline);
  293. try {
  294. UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
  295. if (response.getResult() == DocWriteResponse.Result.UPDATED) {
  296. //log.info("文档更新成功!");
  297. } else if (response.getResult() == DocWriteResponse.Result.DELETED) {
  298. log.error("\"index={},type={},id={}\"的文档已被删除,无法更新!", response.getIndex(), response.getType(), response.getId());
  299. } else if (response.getResult() == DocWriteResponse.Result.NOOP) {
  300. log.error("操作没有被执行!");
  301. }
  302. ReplicationResponse.ShardInfo shardInfo = response.getShardInfo();
  303. if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
  304. log.error("部分分片副本未处理");
  305. }
  306. if (shardInfo.getFailed() > 0) {
  307. for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
  308. String reason = failure.reason();
  309. log.error("未处理原因:{}", reason);
  310. }
  311. }
  312. } catch (ElasticsearchException e) {
  313. if (e.status() == RestStatus.NOT_FOUND) {
  314. log.error("不存在这个文档,请检查参数!");
  315. } else if (e.status() == RestStatus.CONFLICT) {
  316. log.error("版本冲突异常!");
  317. }
  318. log.error("更新失败!:{},脚本:{},id:{}",e.getMessage(),script,id);
  319. }
  320. }
  321. /**
  322. * 批量增加文档
  323. *
  324. * @param indexName
  325. * @param typeName
  326. * @param esMappingTypes 添加的文档列表
  327. * @throws IOException
  328. */
  329. public List<String> bulkAdd(String indexName, String typeName, List<? extends IESMappingType> esMappingTypes) throws IOException {
  330. List<String> failureList = new ArrayList<>();
  331. BulkRequest bulkRequest = new BulkRequest();
  332. if (CollectionUtils.isNotEmpty(esMappingTypes)) {
  333. for (IESMappingType mappingType : esMappingTypes) {
  334. IndexRequest request = new IndexRequest(indexName, typeName, mappingType.generateDocId()).source(JSON.toJSONString(mappingType), XContentType.JSON);
  335. bulkRequest.add(request);
  336. }
  337. }
  338. // 超时时间(2分钟)
  339. bulkRequest.timeout(TimeValue.timeValueMinutes(2L));
  340. // 刷新策略
  341. bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
  342. if (bulkRequest.numberOfActions() == 0) {
  343. log.error("参数错误,批量增加操作失败!");
  344. return new ArrayList<>();
  345. }
  346. BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
  347. // 全部操作成功
  348. if (!bulkResponse.hasFailures()) {
  349. // log.info("批量增加操作成功!");
  350. } else {
  351. for (BulkItemResponse bulkItemResponse : bulkResponse) {
  352. if (bulkItemResponse.isFailed()) {
  353. BulkItemResponse.Failure failure = bulkItemResponse.getFailure();
  354. log.error("\"index={}, type={}, id={}\"的文档增加失败!", failure.getIndex(), failure.getType(), failure.getId());
  355. log.error("增加失败详情: {}", failure.getMessage());
  356. failureList.add(failure.getId());
  357. log.error("新增失败的货品id:{}",failureList);
  358. return failureList;
  359. } else {
  360. // log.info("\"index={}, type={}, id={}\"的文档增加成功!", bulkItemResponse.getIndex(), bulkItemResponse.getType(), bulkItemResponse.getId());
  361. }
  362. }
  363. }
  364. return new ArrayList<>();
  365. }
  366. /**
  367. * 根据条件删除es数据
  368. *
  369. * @param indexName 索引名称
  370. * @param bigBoolQueryBuilder
  371. * @return 删除条数
  372. * @author shixiaorui
  373. * @date 2020/8/31 18:27
  374. */
  375. public Long delByEsQuery(String indexName, BoolQueryBuilder bigBoolQueryBuilder) {
  376. DeleteByQueryRequest request =
  377. new DeleteByQueryRequest(indexName);
  378. request.setQuery(bigBoolQueryBuilder);
  379. try {
  380. BulkByScrollResponse bulkResponse =
  381. client.deleteByQuery(request, RequestOptions.DEFAULT);
  382. return bulkResponse.getDeleted();
  383. } catch (ElasticsearchException e) {
  384. if (e.status() == RestStatus.CONFLICT) {
  385. log.error("版本冲突!");
  386. }
  387. log.error("删除失败!:{}", e.getMessage());
  388. } catch (IOException ioExp) {
  389. log.error("删除失败:{}", ioExp.getMessage());
  390. }
  391. return 0L;
  392. }
  393. /**
  394. * 批量更新文档
  395. *
  396. * @param indexName
  397. * @param typeName
  398. * @param esMappingTypes
  399. * @throws IOException
  400. */
  401. public List<String> bulkUpdate(String indexName, String typeName, List<? extends IESMappingType> esMappingTypes) throws IOException {
  402. List<String> failureList = new ArrayList<>();
  403. BulkRequest bulkRequest = new BulkRequest();
  404. if (CollectionUtils.isNotEmpty(esMappingTypes)) {
  405. for (IESMappingType mappingType : esMappingTypes) {
  406. UpdateRequest request=new UpdateRequest(indexName, typeName, mappingType.generateDocId())
  407. .doc(JSON.toJSONString(mappingType), XContentType.JSON);
  408. // true,表明如果文档不存在,则新更新的文档内容作为新的内容插入文档,
  409. //这个和scriptedUpsert的区别是:更新文档的两种不同方式,有的使用doc方法更新有的使用脚本更新
  410. request.docAsUpsert(true);
  411. // 是否将文档内容作为结果返回,默认是禁止的
  412. request.fetchSource(false);
  413. bulkRequest.add(request);
  414. }
  415. }
  416. if (bulkRequest.numberOfActions() == 0) {
  417. log.error("参数错误,批量更新操作失败!");
  418. return new ArrayList<>();
  419. }
  420. bulkRequest.timeout(TimeValue.timeValueMinutes(2L));
  421. bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
  422. BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
  423. if (!bulkResponse.hasFailures()) {
  424. // log.info("批量更新操作成功!");
  425. } else {
  426. for (BulkItemResponse bulkItemResponse : bulkResponse) {
  427. if (bulkItemResponse.isFailed()) {
  428. BulkItemResponse.Failure failure = bulkItemResponse.getFailure();
  429. log.error("\"index={}, type={}, id={}\"的文档更新失败!", failure.getIndex(), failure.getType(), failure.getId());
  430. log.error("更新失败详情: {}", failure.getMessage());
  431. failureList.add(failure.getId());
  432. log.error("更新失败的货品id: {}", failureList);
  433. return failureList;
  434. }/* else {
  435. log.info("\"index={}, type={}, id={}\"的文档更新成功!", bulkItemResponse.getIndex(), bulkItemResponse.getType(), bulkItemResponse.getId());
  436. }*/
  437. }
  438. }
  439. return failureList;
  440. }
  441. /**
  442. * 批量删除文档
  443. *
  444. * @param indexName
  445. * @param typeName
  446. * @param docIds
  447. * @throws IOException
  448. */
  449. public boolean bulkDelete(String indexName, String typeName, List<String> docIds) throws IOException {
  450. BulkRequest bulkRequest = new BulkRequest();
  451. if (CollectionUtils.isNotEmpty(docIds)) {
  452. for (String docId : docIds) {
  453. DeleteRequest request = new DeleteRequest(indexName, typeName, docId);
  454. bulkRequest.add(request);
  455. }
  456. }
  457. if (bulkRequest.numberOfActions() == 0) {
  458. log.error("操作失败,请检查参数!");
  459. return false;
  460. }
  461. bulkRequest.timeout(TimeValue.timeValueMinutes(2L));
  462. bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
  463. BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
  464. if (!bulkResponse.hasFailures()) {
  465. log.info("批量删除操作成功!");
  466. return true;
  467. } else {
  468. for (BulkItemResponse bulkItemResponse : bulkResponse) {
  469. if (bulkItemResponse.isFailed()) {
  470. BulkItemResponse.Failure failure = bulkItemResponse.getFailure();
  471. log.error("\"index={}, type={}, id={}\"的文档删除失败!", failure.getIndex(), failure.getType(), failure.getId());
  472. log.error("删除失败详情: {}", failure.getMessage());
  473. return false;
  474. }
  475. }
  476. return false;
  477. }
  478. }
  479. /**
  480. * 批量查找文档
  481. *
  482. * @param indexName
  483. * @return
  484. * @throws IOException
  485. */
  486. public List<Map<String, Object>> multiGet(String indexName, String typeName, List<String> docIds) throws IOException {
  487. List<Map<String, Object>> resultList = new ArrayList<>();
  488. MultiGetRequest request = new MultiGetRequest();
  489. if (CollectionUtils.isNotEmpty(docIds)) {
  490. for (String docId : docIds) {
  491. request.add(new MultiGetRequest.Item(indexName, typeName, docId));
  492. }
  493. }
  494. request.realtime(false);
  495. request.refresh(true);
  496. MultiGetResponse response = client.mget(request, RequestOptions.DEFAULT);
  497. List<Map<String, Object>> list = parseMGetResponse(response);
  498. if (!list.isEmpty()) {
  499. resultList.addAll(list);
  500. }
  501. return resultList;
  502. }
  503. private List<Map<String, Object>> parseMGetResponse(MultiGetResponse response) {
  504. List<Map<String, Object>> list = new ArrayList<>();
  505. MultiGetItemResponse[] responses = response.getResponses();
  506. for (MultiGetItemResponse item : responses) {
  507. GetResponse getResponse = item.getResponse();
  508. if (Objects.nonNull(getResponse)) {
  509. if (!getResponse.isExists()) {
  510. log.error("\"index={}, type={}, id={}\"的文档查找失败,请检查参数!", getResponse.getIndex(), getResponse.getType(), getResponse.getId());
  511. } else {
  512. list.add(getResponse.getSourceAsMap());
  513. }
  514. } else {
  515. MultiGetResponse.Failure failure = item.getFailure();
  516. ElasticsearchException e = (ElasticsearchException) failure.getFailure();
  517. if (e.status() == RestStatus.NOT_FOUND) {
  518. log.error("\"index={}, type={}, id={}\"的文档不存在!", failure.getIndex(), failure.getType(), failure.getId());
  519. } else if (e.status() == RestStatus.CONFLICT) {
  520. log.error("\"index={}, type={}, id={}\"的文档版本冲突!", failure.getIndex(), failure.getType(), failure.getId());
  521. }
  522. }
  523. }
  524. return list;
  525. }
  526. /**
  527. * 根据条件搜索日志内容(参数level和messageKey不能同时为空)
  528. *
  529. * @param level 日志级别,可以为空
  530. * @param messageKey 日志信息关键字,可以为空
  531. * @param startTime 日志起始时间,可以为空
  532. * @param endTime 日志结束时间,可以为空
  533. * @param size 返回记录数,可以为空,默认最大返回10条。该值必须小于10000,如果超过10000请使用 {@link #queryAllByConditions}
  534. * @return
  535. * @throws IOException
  536. */
  537. public List<Map<String, Object>> queryByConditions(String indexName, String typeName, String level, String messageKey, Long startTime, Long endTime, Integer size) throws IOException {
  538. List<Map<String, Object>> resultList = new ArrayList<>();
  539. if (StringUtils.isBlank(level) && StringUtils.isBlank(messageKey)) {
  540. log.error("参数level(日志级别)和messageKey(日志信息关键字)不能同时为空!");
  541. return resultList;
  542. }
  543. QueryBuilder query = generateQuery(level, messageKey, startTime, endTime);
  544. FieldSortBuilder order = SortBuilders.fieldSort(TIMESTAMP).order(SortOrder.DESC);
  545. SearchSourceBuilder searchBuilder = new SearchSourceBuilder();
  546. searchBuilder.timeout(TimeValue.timeValueMinutes(2L));
  547. searchBuilder.query(query);
  548. searchBuilder.sort(order);
  549. if (Objects.nonNull(size)) {
  550. searchBuilder.size(size);
  551. }
  552. SearchRequest request = new SearchRequest(indexName).types(typeName);
  553. request.source(searchBuilder);
  554. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
  555. int failedShards = response.getFailedShards();
  556. if (failedShards > 0) {
  557. log.error("部分分片副本处理失败!");
  558. for (ShardSearchFailure failure : response.getShardFailures()) {
  559. String reason = failure.reason();
  560. log.error("分片处理失败原因:{}", reason);
  561. }
  562. }
  563. List<Map<String, Object>> list = parseSearchResponse(response);
  564. if (!list.isEmpty()) {
  565. resultList.addAll(list);
  566. }
  567. return resultList;
  568. }
  569. private QueryBuilder generateQuery(String level, String messageKey, Long startTime, Long endTime) {
  570. // term query(检索level)
  571. TermQueryBuilder levelQuery = null;
  572. if (StringUtils.isNotBlank(level)) {
  573. levelQuery = QueryBuilders.termQuery("level", level.toLowerCase());
  574. }
  575. // match query(检索message)
  576. MatchQueryBuilder messageQuery = null;
  577. if (StringUtils.isNotBlank(messageKey)) {
  578. messageQuery = QueryBuilders.matchQuery("name", messageKey);
  579. }
  580. // range query(检索timestamp)
  581. RangeQueryBuilder timeQuery = QueryBuilders.rangeQuery(TIMESTAMP);
  582. timeQuery.format("epoch_millis");
  583. if (Objects.isNull(startTime)) {
  584. if (Objects.isNull(endTime)) {
  585. timeQuery = null;
  586. } else {
  587. timeQuery.lte(endTime);
  588. }
  589. } else {
  590. if (Objects.isNull(endTime)) {
  591. timeQuery.gte(startTime);
  592. } else {
  593. timeQuery.gte(startTime).lte(endTime);
  594. }
  595. }
  596. // 将上述三个query组合
  597. BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
  598. if (Objects.nonNull(levelQuery)) {
  599. boolQuery.must(levelQuery);
  600. }
  601. if (Objects.nonNull(messageQuery)) {
  602. boolQuery.must(messageQuery);
  603. }
  604. if (Objects.nonNull(timeQuery)) {
  605. boolQuery.must(timeQuery);
  606. }
  607. return boolQuery;
  608. }
  609. private List<Map<String, Object>> parseSearchResponse(SearchResponse response) {
  610. List<Map<String, Object>> resultList = new ArrayList<>();
  611. SearchHit[] hits = response.getHits().getHits();
  612. for (SearchHit hit : hits) {
  613. resultList.add(hit.getSourceAsMap());
  614. }
  615. return resultList;
  616. }
  617. /**
  618. * 查询所有文档id
  619. *
  620. * @return
  621. */
  622. public List<String> queryAllIdByIndexName(String indexName, String typeName) throws IOException {
  623. List<String> resultList = new ArrayList<>();
  624. SearchSourceBuilder searchBuilder = new SearchSourceBuilder();
  625. searchBuilder.size(500);
  626. // 初始化 scroll 上下文
  627. SearchRequest request = new SearchRequest(indexName).types(typeName);
  628. final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));
  629. request.source(searchBuilder).scroll(scroll);
  630. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
  631. String scrollId = response.getScrollId();
  632. SearchHit[] searchHits = response.getHits().getHits();
  633. // 把第一次scroll的数据添加到结果List中
  634. for (SearchHit searchHit : searchHits) {
  635. resultList.add(searchHit.getId());
  636. }
  637. // 通过传递scrollId循环取出所有相关文档
  638. while (searchHits.length > 0) {
  639. SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
  640. scrollRequest.scroll(scroll);
  641. response = client.scroll(scrollRequest, RequestOptions.DEFAULT);
  642. scrollId = response.getScrollId();
  643. searchHits = response.getHits().getHits();
  644. // 循环添加剩下的数据
  645. for (SearchHit searchHit : searchHits) {
  646. resultList.add(searchHit.getId());
  647. }
  648. }
  649. // 清理 scroll 上下文
  650. ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
  651. clearScrollRequest.addScrollId(scrollId);
  652. client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
  653. return resultList;
  654. }
  655. /**
  656. * 根据条件,搜索全部符合的记录(参数level和messageKey不能同时为空)
  657. *
  658. * @param level 日志级别,可以为空
  659. * @param messageKey 日志信息关键字,可以为空
  660. * @param startTime 日志起始时间,可以为空
  661. * @param endTime 日志结束时间,可以为空
  662. * @return
  663. */
  664. public List<Map<String, Object>> queryAllByConditions(String indexName, String typeName, String level, String messageKey, Long startTime, Long endTime) throws IOException {
  665. List<Map<String, Object>> resultList = new ArrayList<>();
  666. if (StringUtils.isBlank(level) && StringUtils.isBlank(messageKey)) {
  667. log.error("参数level(日志级别)和messageKey(日志信息关键字)不能同时为空!");
  668. return resultList;
  669. }
  670. QueryBuilder query = generateQuery(level, messageKey, startTime, endTime);
  671. FieldSortBuilder order = SortBuilders.fieldSort(TIMESTAMP).order(SortOrder.DESC);
  672. SearchSourceBuilder searchBuilder = new SearchSourceBuilder();
  673. searchBuilder.query(query).sort(order);
  674. searchBuilder.size(500);
  675. // 初始化 scroll 上下文
  676. SearchRequest request = new SearchRequest(indexName).types(typeName);
  677. final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));
  678. request.source(searchBuilder).scroll(scroll);
  679. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
  680. String scrollId = response.getScrollId();
  681. SearchHit[] searchHits = response.getHits().getHits();
  682. // 把第一次scroll的数据添加到结果List中
  683. for (SearchHit searchHit : searchHits) {
  684. resultList.add(searchHit.getSourceAsMap());
  685. }
  686. // 通过传递scrollId循环取出所有相关文档
  687. while (searchHits != null && searchHits.length > 0) {
  688. SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
  689. scrollRequest.scroll(scroll);
  690. response = client.scroll(scrollRequest, RequestOptions.DEFAULT);
  691. scrollId = response.getScrollId();
  692. searchHits = response.getHits().getHits();
  693. // 循环添加剩下的数据
  694. for (SearchHit searchHit : searchHits) {
  695. resultList.add(searchHit.getSourceAsMap());
  696. }
  697. }
  698. // 清理 scroll 上下文
  699. ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
  700. clearScrollRequest.addScrollId(scrollId);
  701. client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
  702. return resultList;
  703. }
  704. /**
  705. * 根据条件做分页查询(参数level和messageKey不能同时为空)
  706. *
  707. * @param level 日志级别,可以为空
  708. * @param messageKey 日志信息关键字,可以为空
  709. * @param startTime 日志起始时间,可以为空
  710. * @param endTime 日志结束时间,可以为空
  711. * @param pageNum 当前页码,可以为空(默认设为1)
  712. * @param pageSize 页记录数,可以为空(默认设为10)
  713. * @return
  714. * @throws IOException
  715. */
  716. public SearchPageBean<Map<String, Object>> queryPageByConditions(String indexName, String typeName, String level, String messageKey, Long startTime, Long endTime, Integer pageNum, Integer pageSize) throws IOException {
  717. if (StringUtils.isBlank(level) && StringUtils.isBlank(messageKey)) {
  718. log.error("参数level(日志级别)、messageKey(日志信息关键字)不能同时为空!");
  719. return null;
  720. }
  721. if (Objects.isNull(pageNum)) {
  722. pageNum = 1;
  723. }
  724. if (Objects.isNull(pageSize)) {
  725. pageSize = 10;
  726. }
  727. QueryBuilder query = generateQuery(level, messageKey, startTime, endTime);
  728. FieldSortBuilder order = SortBuilders.fieldSort(TIMESTAMP).order(SortOrder.DESC);
  729. SearchSourceBuilder searchBuilder = new SearchSourceBuilder();
  730. searchBuilder.timeout(TimeValue.timeValueMinutes(2L));
  731. searchBuilder.query(query);
  732. searchBuilder.sort(order);
  733. searchBuilder.from(pageNum - 1).size(pageSize);
  734. SearchRequest request = new SearchRequest(indexName).types(typeName);
  735. request.source(searchBuilder);
  736. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
  737. SearchHits hits = response.getHits();
  738. int totalRecord = (int) hits.getTotalHits();
  739. List<Map<String, Object>> results = new ArrayList<>();
  740. for (SearchHit hit : hits.getHits()) {
  741. results.add(hit.getSourceAsMap());
  742. }
  743. SearchPageBean<Map<String, Object>> page = new SearchPageBean<>();
  744. page.setPageNo(pageNum);
  745. page.setPageSize(pageSize);
  746. page.setTotalPages(totalRecord);
  747. page.setData(results);
  748. return page;
  749. }
  750. /**
  751. * 通用查询
  752. * 复杂查询可以自定义实现RestHighLevelClient
  753. *
  754. * @param indexName 索引
  755. * @param eSMappingType 返回的对象类型
  756. * @param searchSourceBuilder 查询条件
  757. * @param <T> 泛型
  758. * @return pageResult
  759. * @author zhangxh
  760. * @since 2019/07/04
  761. */
  762. public <T> PageResult<T> search(String indexName, Class<T> eSMappingType, SearchSourceBuilder searchSourceBuilder) {
  763. if (eSMappingType == null) {
  764. throw new IllegalArgumentException("eSMappingType can not be null");
  765. }
  766. if (indexName == null) {
  767. throw new ServiceException("indexName 不能为空");
  768. }
  769. SearchRequest searchRequest = new SearchRequest()
  770. .indices(indexName)
  771. .types(eSMappingType.getSimpleName())
  772. .source(searchSourceBuilder);
  773. try {
  774. SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
  775. SearchHits hits = search.getHits();
  776. SearchHit[] hitsArray = hits.getHits();
  777. PageResult<T> pageResult = new PageResult<>();
  778. pageResult.setRecordCount((int) hits.getTotalHits());
  779. List<T> list = new ArrayList<>();
  780. for (SearchHit hit : hitsArray) {
  781. list.add(JsonHelper.parseBean(hit.getSourceAsString(), eSMappingType));
  782. }
  783. pageResult.setResult(list);
  784. // log.info("es查询语句:{}" , searchSourceBuilder.toString());
  785. return pageResult;
  786. } catch (Exception e) {
  787. log.error("查询文档:{},失败:{}", indexName, e.getMessage());
  788. e.printStackTrace();
  789. }
  790. return new PageResult<>();
  791. }
  792. public <T> PageResult<T> searchMore(String indexName, Class<T> eSMappingType, SearchSourceBuilder searchSourceBuilder) {
  793. if (eSMappingType == null) {
  794. throw new IllegalArgumentException("eSMappingType can not be null");
  795. }
  796. if (indexName == null) {
  797. throw new ServiceException("indexName 不能为空");
  798. }
  799. searchSourceBuilder.from(0).size(10000);
  800. SearchRequest searchRequest = new SearchRequest()
  801. .indices(indexName)
  802. .types(eSMappingType.getSimpleName())
  803. .source(searchSourceBuilder);
  804. try {
  805. SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
  806. SearchHits hits = search.getHits();
  807. SearchHit[] hitsArray = hits.getHits();
  808. PageResult<T> pageResult = new PageResult<>();
  809. pageResult.setRecordCount((int) hits.getTotalHits());
  810. List<T> list = new ArrayList<>();
  811. for (SearchHit hit : hitsArray) {
  812. list.add(JsonHelper.parseBean(hit.getSourceAsString(), eSMappingType));
  813. }
  814. pageResult.setResult(list);
  815. // log.info("es查询语句:{}" , searchSourceBuilder.toString());
  816. return pageResult;
  817. } catch (Exception e) {
  818. log.error("查询文档:{},失败:{}", indexName, e.getMessage());
  819. e.printStackTrace();
  820. }
  821. return new PageResult<>();
  822. }
  823. private XContentBuilder generateBuilder() throws IOException {
  824. XContentBuilder builder = XContentFactory.jsonBuilder();
  825. builder.startObject();
  826. builder.startObject("properties");
  827. builder.startObject("message");
  828. builder.field("type", "text");
  829. // 为message字段,设置分词器为 ik_smart(最粗粒度)
  830. builder.field("analyzer", "ik_smart");
  831. builder.endObject();
  832. builder.startObject(TIMESTAMP);
  833. builder.field("type", "date");
  834. // 设置 日志时间的格式为 毫秒数的long类型
  835. builder.field("format", "epoch_millis");
  836. builder.endObject();
  837. builder.endObject();
  838. builder.endObject();
  839. return builder;
  840. }
  841. /**
  842. * 根据IESMappingType 的实现类,生成创建mappingType的 XContentBuilder
  843. *
  844. * @param esMapTypeClass
  845. * @return
  846. * @throws IOException
  847. */
  848. public XContentBuilder buildXContentBuilder(String index, Class<? extends IESMappingType> esMapTypeClass) throws IOException {
  849. XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
  850. // 处理对象属性类型
  851. dealObj(builder, esMapTypeClass);
  852. builder.endObject();
  853. return builder;
  854. }
  855. /**
  856. * 根据对象的es属性注解判断是否进行属性处理
  857. *
  858. * @param builder
  859. * @param esMapTypeClass
  860. * @throws IOException
  861. */
  862. private void dealObj(XContentBuilder builder, Class<? extends IESMappingType> esMapTypeClass) throws IOException {
  863. // 子属性放到该索引下
  864. builder.startObject("properties");
  865. for (Field field : esMapTypeClass.getDeclaredFields()) {
  866. ESField fieldProp = field.getAnnotation(ESField.class);
  867. if (fieldProp != null) {
  868. dealField(builder, field, fieldProp);
  869. }
  870. }
  871. //判断对象是否有 @Suggestable 注解,有则添加 suggest 字段
  872. EnableSuggest suggest = esMapTypeClass.getAnnotation(EnableSuggest.class);
  873. if (suggest != null) {
  874. String analyzer = suggest.analyzerType().name();
  875. String suggestName = suggest.suggestName();
  876. builder.startObject(suggestName)
  877. .field("type", "completion")
  878. .field("index_analyzer", analyzer)
  879. .field("search_analyzer", analyzer)
  880. .field("payloads", "true")
  881. .field("preserve_position_increments", false)
  882. .field("preserve_separators", false)
  883. .endObject();
  884. }
  885. builder.endObject();
  886. }
  887. /**
  888. * 处理对象的属性类型
  889. *
  890. * @param builder
  891. * @param field 属性
  892. * @param fieldProp 属性注解信息
  893. * @throws IOException
  894. */
  895. private void dealField(XContentBuilder builder, Field field, ESField fieldProp) throws IOException {
  896. try {
  897. if (List.class.isAssignableFrom(field.getType()) || field.getType().isArray()) {
  898. //list 类型的 嵌套类型和对象数组
  899. builder.startObject(field.getName());// 这里如果是startArray就会有问题.
  900. if (fieldProp.fieldType() == ESFieldType.NESTED) {
  901. //嵌套类型(要查询对象信息)
  902. builder.field("type", ESFieldType.NESTED.getTypeValue());
  903. }else{
  904. //对象数组(只是保存对象信息)
  905. builder.field("type", ESFieldType.OBJECT.getTypeValue());
  906. }
  907. String className = "";
  908. Type fc = field.getGenericType();
  909. if (fc instanceof ParameterizedType) {
  910. ParameterizedType pt = (ParameterizedType) fc;
  911. className = pt.getActualTypeArguments()[0].toString().replace("class ", "");
  912. } else if (field.getType().isArray()) {
  913. className = field.getGenericType().toString().replace("class [L", "")
  914. .replace("/", ".").replace(";", "");
  915. }
  916. Class clazz = Class.forName(className);
  917. if (IESMappingType.class.isAssignableFrom(clazz) || clazz.getAnnotation(ESDocObject.class) != null) {
  918. dealObj(builder, clazz);
  919. } else if (clazz.isPrimitive() || isSimpleType(clazz)) {
  920. builder.field("type", ESFieldType.STRING.getTypeValue())
  921. .field("index", ESAnalyzer.not_analyzed.name()).field("store", fieldProp.isStore());
  922. }
  923. builder.endObject();
  924. } else if (Map.class.isAssignableFrom(field.getType())) {
  925. System.out.println("Map:" + field.getName());
  926. } else {
  927. // 处理简单对象
  928. if (isSimpleType(field.getType())) {
  929. dealSimpleObjField(builder, field.getName(), fieldProp);
  930. return;
  931. }
  932. // 如果是复杂的组合类型,继承于ESMapTypeI,则进行递归处理
  933. String className = field.getGenericType().toString().replace("class ", "");
  934. Class complexClazz = Class.forName(className);
  935. if (IESMappingType.class.isAssignableFrom(complexClazz)) {
  936. builder.startObject(field.getName());
  937. if (fieldProp.fieldType() == ESFieldType.NESTED) {
  938. builder.field("type", ESFieldType.NESTED.getTypeValue());
  939. }
  940. dealObj(builder, complexClazz);
  941. builder.endObject();
  942. }
  943. }
  944. } catch (Exception e) {
  945. log.error("创建mapping出错...", e);
  946. }
  947. }
  948. /**
  949. * 判断是否是简单的对象.
  950. *
  951. * @param cls
  952. * @return
  953. */
  954. private static boolean isSimpleType(Class cls) {
  955. if (cls == String.class || cls == Integer.class || cls == BigDecimal.class || cls == Date.class || cls == int.class || cls == long.class || cls == Long.class) {
  956. return true;
  957. } else {
  958. return false;
  959. }
  960. }
  961. /**
  962. * 处理对象类型的域值,处理已经是最简单对象的field
  963. */
  964. public void dealSimpleObjField(XContentBuilder mapbuilder, String fieldName, ESField eSMapType) throws IOException {
  965. mapbuilder.startObject(fieldName).field("store", eSMapType.isStore()).field("type", eSMapType.fieldType().getTypeValue());
  966. ESAnalyzer esAnalyzer = eSMapType.analyzerType();
  967. if (esAnalyzer != ESAnalyzer.not_analyzed) {
  968. if (esAnalyzer == ESAnalyzer.analyzed) {
  969. mapbuilder.field("index", "true");
  970. } else {
  971. mapbuilder.field("index", "true").
  972. field("search_analyzer", esAnalyzer.name())
  973. .field("analyzer", esAnalyzer.name());
  974. }
  975. } else if (esAnalyzer == ESAnalyzer.not_analyzed) {
  976. mapbuilder.field("index", "false");
  977. }
  978. mapbuilder.endObject();
  979. }
  980. /**
  981. * es聚合分组求和
  982. *
  983. * @param indexName 索引名称
  984. * @param groupKey 分组的key
  985. * @param sumKey 求和的key
  986. * @return Map
  987. * @author shixiaorui
  988. * @date 2020/11/12 10:29
  989. */
  990. public Map<String, Long> groupKeySum(String indexName, String eSMappingTypeName, SearchSourceBuilder searchSourceBuilder, String groupKey, String sumKey) {
  991. try {
  992. SearchRequest searchRequest = new SearchRequest()
  993. .indices(indexName)
  994. .types(eSMappingTypeName)
  995. .source(searchSourceBuilder);
  996. String aggName = groupKey + "_key";//分组字段别名
  997. String aggField = sumKey + "_key";//求和字段别名
  998. //分组groupKey,求和sumKey
  999. TermsAggregationBuilder field = AggregationBuilders.terms(aggName).field(groupKey);
  1000. field.subAggregation(AggregationBuilders.sum(aggField).field(sumKey));
  1001. searchSourceBuilder.aggregation(field);
  1002. searchRequest.source(searchSourceBuilder);
  1003. //执行查询
  1004. SearchResponse response = client.search(searchRequest);
  1005. //获取搜索的文档结果
  1006. Map<String, Aggregation> aggMap = response.getAggregations().getAsMap();
  1007. Terms gradeTerms = (Terms) aggMap.get(aggName);
  1008. Map<String, Long> returnMap = new HashMap<>();
  1009. Map<String, Long> valueResult = new LinkedHashMap<>();
  1010. if(null!=gradeTerms.getBuckets()&&gradeTerms.getBuckets().size()>0){
  1011. for (Terms.Bucket bucket : gradeTerms.getBuckets()) {
  1012. double num = ((Sum) bucket.getAggregations().get(aggField)).getValue();
  1013. returnMap.put(bucket.getKeyAsString(), new Double(num).longValue());
  1014. }
  1015. //排序
  1016. returnMap.entrySet().stream()
  1017. .sorted(Map.Entry
  1018. .comparingByValue(Comparator.reverseOrder()))
  1019. .forEachOrdered(b->valueResult.put(b.getKey(), b.getValue()));
  1020. return valueResult;
  1021. }
  1022. return new HashMap<>();
  1023. } catch (Exception ex) {
  1024. ex.printStackTrace();
  1025. return null;
  1026. }
  1027. }
  1028. /**
  1029. * 查询,包含下钻聚合数据
  1030. *
  1031. * @param indexName 索引
  1032. * @param eSMappingType 返回的对象类型
  1033. * @param searchSourceBuilder 查询条件
  1034. * @return pageResult
  1035. * @author hucm
  1036. * @since 2021/08/17
  1037. */
  1038. public IndexSearchResponse searchGroupBy(String indexName, Class eSMappingType, SearchSourceBuilder searchSourceBuilder, MallEsSearchFormDTO form) {
  1039. if (eSMappingType == null) {
  1040. throw new IllegalArgumentException("eSMappingType can not be null");
  1041. }
  1042. if (indexName == null) {
  1043. throw new ServiceException("indexName 不能为空");
  1044. }
  1045. SearchRequest searchRequest = new SearchRequest()
  1046. .indices(indexName)
  1047. .types(eSMappingType.getSimpleName())
  1048. .source(searchSourceBuilder);
  1049. try {
  1050. SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
  1051. SearchHits hits = search.getHits();
  1052. SearchHit[] hitsArray = hits.getHits();
  1053. // 封装返回结果
  1054. IndexSearchResponse response = new IndexSearchResponse();
  1055. // 放入源数据
  1056. response.setOriginHits(hits);
  1057. List<String> sources = new ArrayList<>();
  1058. for (SearchHit hit : hits.getHits()) {
  1059. sources.add(hit.getSourceAsString());
  1060. }
  1061. response.putReslutData(sources);
  1062. // 聚合结果
  1063. response.putResultAggs(agg2Map(search.getAggregations()));
  1064. // 总数据
  1065. response.setPageNum(form.getPageNo());
  1066. response.setPageSize(form.getPageSize());
  1067. response.setTotalCount((int) hits.getTotalHits());
  1068. return response;
  1069. } catch (Exception e) {
  1070. log.error("查询文档:{},失败:{}", indexName, e.getMessage());
  1071. e.printStackTrace();
  1072. }
  1073. return null;
  1074. }
  1075. /**
  1076. * 处理一个聚合对象数据{@link Aggregations}
  1077. *
  1078. * @param aggregations
  1079. * @return Map{key:一个聚合的名称,value:聚合后的桶数据}
  1080. */
  1081. public Map<String, Object> agg2Map(Aggregations aggregations) {
  1082. Map<String, Object> resultMap = new HashMap<>();
  1083. if (aggregations == null) {
  1084. return resultMap;
  1085. }
  1086. for (Aggregation aggregation : aggregations) {
  1087. resultMap.put(aggregation.getName(), dealOneAggregation(aggregation));
  1088. }
  1089. return resultMap;
  1090. }
  1091. /**
  1092. * 处理一个聚合对象
  1093. *
  1094. * @param aggregation {@link Aggregation}
  1095. * @return 如果只有一个桶数据, 则返回对象, 如果有多个桶数据, 则返回数组
  1096. */
  1097. public Object dealOneAggregation(Aggregation aggregation) {
  1098. if (aggregation instanceof ParsedStringTerms) {
  1099. Collection<? extends Terms.Bucket> buckets = ((ParsedStringTerms) aggregation).getBuckets();
  1100. return dealBunkets(buckets);
  1101. } else if (aggregation instanceof ParsedDoubleTerms) {
  1102. Collection<? extends Terms.Bucket> buckets = ((ParsedDoubleTerms) aggregation).getBuckets();
  1103. return dealBunkets(buckets);
  1104. } else if (aggregation instanceof ParsedLongTerms) {
  1105. Collection<? extends Terms.Bucket> buckets = ((ParsedLongTerms) aggregation).getBuckets();
  1106. return dealBunkets(buckets);
  1107. } else if (aggregation instanceof UnmappedTerms) {
  1108. Collection<? extends Terms.Bucket> buckets = ((UnmappedTerms) aggregation).getBuckets();
  1109. return dealBunkets(buckets);
  1110. } else if (aggregation instanceof ParsedNested) {
  1111. Aggregations aggregations = ((ParsedNested) aggregation).getAggregations();
  1112. return agg2list(aggregations);
  1113. } else if (aggregation instanceof ParsedAvg) {
  1114. return aggregation.getName();
  1115. } else {
  1116. throw new IllegalArgumentException("未知聚合类型,不可处理");
  1117. }
  1118. }
  1119. /**
  1120. * 处理一个聚合下边的一个或多个桶数据
  1121. *
  1122. * @param buckets
  1123. * @return 如果有一个桶, 那么就返回一个对象, 而不是列表 如果有多个桶,则返回列表 如果没有值,则返回一个空对象
  1124. */
  1125. public Object dealBunkets(Collection<? extends Terms.Bucket> buckets) {
  1126. List<Object> list = new ArrayList<>();
  1127. for (Terms.Bucket bucket : buckets) {
  1128. list.add(dealOneBunket(bucket));
  1129. }
  1130. return list.isEmpty() ? new Object() : list.size() == 1 ? list.get(0) : list;
  1131. }
  1132. /**
  1133. * 处理一个bunkey
  1134. *
  1135. * @param bucket
  1136. * @return 如果没有子查询返回bunkey中的值[String]
  1137. * 如果有子查询,返回一个对应的map对象[HashMap]--{key:bunketKey,value:子查询返回的map}
  1138. */
  1139. public Object dealOneBunket(Terms.Bucket bucket) {
  1140. Object params = null;
  1141. if (bucket.getAggregations().iterator().hasNext()) {
  1142. params = agg2list(bucket.getAggregations());
  1143. }
  1144. if (params == null) {
  1145. return bucket.getKey();// 没有子查询
  1146. } else if (params instanceof List) {
  1147. List<Object> resultList = (List) params;
  1148. if (resultList.size() == 1) {
  1149. return resultList.get(0);
  1150. } else if (resultList.size() > 1) {
  1151. Map<String, Object> resultMap = new HashMap<>();
  1152. resultMap.put(bucket.getKey().toString(), resultList);
  1153. return resultMap;
  1154. } else {
  1155. return resultList;
  1156. }
  1157. } else {
  1158. // 没有子查询
  1159. Map<String, Object> resultMap = new HashMap<>();
  1160. resultMap.put(bucket.getKey().toString(), params);
  1161. return resultMap;
  1162. }
  1163. }
  1164. /**
  1165. * 处理子聚合的方法
  1166. *
  1167. * @param aggregations
  1168. * @return
  1169. * @author of1081
  1170. */
  1171. public Object agg2list(Aggregations aggregations) {
  1172. List<Object> resultList = new ArrayList<>();
  1173. for (Aggregation aggregation : aggregations) {
  1174. if (!(aggregation instanceof InternalAvg)) {
  1175. resultList.add(dealOneAggregation(aggregation));
  1176. }
  1177. }
  1178. return resultList.isEmpty() ? new Object() : resultList.size() == 1 ? resultList.get(0) : resultList;
  1179. }
  1180. }

IndexSearchResponse

  1. import com.alibaba.fastjson.JSON;
  2. import com.alibaba.fastjson.JSONArray;
  3. import org.elasticsearch.search.SearchHits;
  4. import java.util.ArrayList;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import java.util.Map;
  8. /**
  9. * @author liangck
  10. * @version 1.0
  11. * @since 15/8/12 11:02
  12. */
  13. public class IndexSearchResponse {
  14. /**
  15. * result中的聚合结果
  16. **/
  17. private static final String AGGS_RESULT = "aggs";
  18. /**
  19. * result中的查询结果数据
  20. **/
  21. private static final String DATA_RESULT = "data";
  22. /**
  23. * 结果总数
  24. */
  25. private int totalCount;
  26. /**
  27. * 当前页码
  28. */
  29. private int pageNum;
  30. /**
  31. * 每页数据条数
  32. */
  33. private int pageSize;
  34. /**
  35. * 数据结果集
  36. */
  37. private Map<String, Object> result = new HashMap<>();
  38. /**
  39. * 查询的源结果
  40. */
  41. private SearchHits originHits;
  42. /**
  43. * 无参数构造器
  44. */
  45. public IndexSearchResponse() {
  46. }
  47. /**
  48. * 根据结果纪录总数,当前查询页码,每页数据条数 构造返回结果集
  49. *
  50. * @param totalCount 查询到的数据总条数
  51. * @param pageNum 当前页码
  52. * @param pageSize 每页数据条数
  53. */
  54. public IndexSearchResponse(int totalCount, int pageNum, int pageSize) {
  55. this(totalCount, pageNum, pageSize, null);
  56. }
  57. /**
  58. * 根据结果纪录总数,当前查询页码,每页数据条数 构造返回结果集
  59. *
  60. * @param totalCount 查询到的数据总条数
  61. * @param pageNum 当前页码
  62. * @param pageSize 每页数据条数
  63. * @param result 数据集
  64. */
  65. public IndexSearchResponse(int totalCount, int pageNum, int pageSize,
  66. Map<String, Object> result) {
  67. this.totalCount = totalCount;
  68. this.pageNum = pageNum;
  69. this.pageSize = pageSize;
  70. this.result = result;
  71. }
  72. /**
  73. * 放入聚合结果
  74. *
  75. * @param aggResult 聚合结果
  76. */
  77. public void putResultAggs(Object aggResult) {
  78. result.put(AGGS_RESULT, aggResult);
  79. }
  80. /**
  81. * 放入查询结果数据
  82. *
  83. * @param data 查询结果数据
  84. */
  85. public void putReslutData(Object data) {
  86. result.put(DATA_RESULT, data);
  87. }
  88. /**
  89. * 获取聚合结果
  90. *
  91. * @return
  92. */
  93. public Object getResultAgg() {
  94. return result.get(AGGS_RESULT);
  95. }
  96. /**
  97. * 获取查询结果数据
  98. *
  99. * @return
  100. */
  101. public Object getResultData() {
  102. return result.get(DATA_RESULT);
  103. }
  104. /**
  105. * 返回结果数据的json字符串,方便进行反序列化
  106. *
  107. * @return
  108. */
  109. public String getResultDataJsonString() {
  110. return (result.get(DATA_RESULT) == null) ? null
  111. : JSON.toJSONString(result.get(DATA_RESULT))
  112. .replace("[\"{", "[{").replace("}\"]", "}]")
  113. .replace("\\", "").replace("}\"", "}")
  114. .replace("\"{", "{");
  115. }
  116. /**
  117. * 返回指定类型的查询数据结果
  118. *
  119. * @param clazz
  120. * @param <T>
  121. * @return
  122. */
  123. public <T> List<T> getResultDataBeans(Class<T> clazz) {
  124. return getResultDataJsonString() == null ? new ArrayList() : JSONArray
  125. .parseArray(getResultDataJsonString(), clazz);
  126. }
  127. public int getTotalCount() {
  128. return totalCount;
  129. }
  130. public void setTotalCount(int totalCount) {
  131. this.totalCount = totalCount;
  132. }
  133. public int getPageNum() {
  134. return pageNum;
  135. }
  136. public void setPageNum(int pageNum) {
  137. this.pageNum = pageNum;
  138. }
  139. public int getPageSize() {
  140. return pageSize;
  141. }
  142. public void setPageSize(int pageSize) {
  143. this.pageSize = pageSize;
  144. }
  145. public Map<String, Object> getResult() {
  146. return result;
  147. }
  148. public void setResult(Map<String, Object> result) {
  149. this.result = result;
  150. }
  151. public SearchHits getOriginHits() {
  152. return originHits;
  153. }
  154. public void setOriginHits(SearchHits originHits) {
  155. this.originHits = originHits;
  156. }
  157. @Override
  158. public String toString() {
  159. return "[{totalCount:" + totalCount + "},{pageNum:" + pageNum
  160. + "},{pageSize:" + pageSize + "}],{result:" + result + "}]";
  161. }
  162. }

ESDocObject

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(ElementType.TYPE)
  3. public @interface ESDocObject {
  4. }

ESField

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(ElementType.FIELD)
  3. public @interface ESField {
  4. /**
  5. * 字段名称
  6. *
  7. * @return
  8. */
  9. public String fieldName() default "";
  10. /**
  11. * 字段类型,默认为string
  12. *
  13. * @return
  14. */
  15. public ESFieldType fieldType() default ESFieldType.TEXT;
  16. /**
  17. * 分词器,默认不进行分词
  18. *
  19. * @return
  20. */
  21. ESAnalyzer analyzerType() default ESAnalyzer.not_analyzed;
  22. /**
  23. * 是否存储,默认为是
  24. *
  25. * @return
  26. */
  27. public boolean isStore() default true;
  28. }

EnableSuggest

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(ElementType.TYPE)
  3. public @interface EnableSuggest {
  4. String suggestName() default "suggest";
  5. /**
  6. * 分词器
  7. *
  8. * @return {@link ESAnalyzer}
  9. */
  10. ESAnalyzer analyzerType() default ESAnalyzer.ik_smart;
  11. }

IESMappingType

  1. /**
  2. * <p>
  3. * es 文档数据类型,所有定义为es文档的bean 必须实现该接口
  4. * </p>
  5. *
  6. * @author liangck
  7. * @version 1.0
  8. * @since 15/8/9 12:20
  9. */
  10. public interface IESMappingType {
  11. /**
  12. * 生成文档ID
  13. * @return 文档ID
  14. */
  15. String generateDocId();
  16. /**
  17. * 返回该文档对象进行索引的field, 用于反射调用生成MapType
  18. *
  19. * @return {@link Field}
  20. */
  21. public Field[] foundTypeField();
  22. }

ESAnalyzer

  1. /**
  2. * of1081_yxd on 2015/1/7. Description: ES 内置分析器
  3. */
  4. public enum ESAnalyzer {
  5. /**
  6. * standard tokenizer, standard filter, lower case filter, stop filter
  7. */
  8. standard(),
  9. /**
  10. * lower case tokenizer
  11. */
  12. simple(),
  13. /**
  14. * ik_max_word
  15. */
  16. ik_max_word(),
  17. /**
  18. * ik_max_word
  19. */
  20. ik_smart(),
  21. /**
  22. * lower case tokenizer, stop filter
  23. */
  24. stop(),
  25. /**
  26. * 不分词,内容整体作为一个token(not_analyzed)
  27. */
  28. keyword(),
  29. /**
  30. * 正则表达式分词,默认匹配\W+
  31. */
  32. whitespace(),
  33. /**
  34. * 各种语言
  35. */
  36. // lang(),
  37. /**
  38. * standard tokenizer, standard filter, lower case filter, stop filter,
  39. * snowball filter
  40. */
  41. snowball(),
  42. /**
  43. * 不进行索引
  44. */
  45. not_analyzed(),
  46. /**
  47. * 进行索引
  48. */
  49. analyzed(),
  50. /**
  51. * Ansj搜索条件分词
  52. */
  53. ansj_query(),
  54. /**
  55. * Ansj索引文档分词
  56. */
  57. ansj_index(),
  58. /**
  59. * Ansj智能分词,即索引文档时使用ansj_index,搜索文档时使用ansj_query分词
  60. */
  61. ansj_auto(),
  62. /**
  63. * 一个Tokenizer, 零个或多个Token Filter, 零个或多个Char Filter
  64. */
  65. ESAnalyzer() {
  66. }
  67. }

ESFieldType

  1. /**
  2. * of1081_yxd on 2015/1/6. Description:索引-映射结构中字段类型.
  3. */
  4. public enum ESFieldType {
  5. /**
  6. * string 数据类型
  7. */
  8. STRING("string"),
  9. /**
  10. * string 数据类型
  11. */
  12. TEXT("text"),
  13. /**
  14. * keyword 全局查询文本类型
  15. */
  16. KEYWORD("keyword"),
  17. /**
  18. * double 数据类型
  19. */
  20. DOUBLE("double"),
  21. /**
  22. * nested类型
  23. */
  24. NESTED("nested"),
  25. /**
  26. * object类型
  27. */
  28. OBJECT("object"),
  29. /**
  30. * boolean 数据类型
  31. */
  32. BOOLEAN("boolean"),
  33. /**
  34. * integer 数据类型
  35. */
  36. INTEGER("integer"),
  37. /**
  38. * date 数据类型
  39. */
  40. DATE("date"),
  41. /**
  42. * long 数据类型
  43. */
  44. LONG("long");
  45. /**
  46. * ES中数据类型标识
  47. */
  48. private String typeValue;
  49. ESFieldType(String typeValue) {
  50. this.typeValue = typeValue;
  51. }
  52. public String getTypeValue() {
  53. return typeValue;
  54. }
  55. }

IkAnalzyerUtil

  1. @Slf4j
  2. public class IkAnalzyerUtil {
  3. /**
  4. * 使用IK分词器 进行分词
  5. *
  6. * @param phrase
  7. * @return
  8. */
  9. public static List<String> segmentPhraseByIk(String phrase) {
  10. if (phrase == null)
  11. throw new NullPointerException("待分词短语不能为空!");
  12. // 构建IK分词器,使用smart分词模式
  13. Analyzer analyzer = null;
  14. try {
  15. analyzer = new IKAnalyzer(true);
  16. } catch (Exception e) {
  17. // e.printStackTrace();\
  18. log.error("use IK has error {}", e.getLocalizedMessage());
  19. return new ArrayList<>();
  20. }
  21. //TODO ik分詞有坑
  22. return segmentPhraseByAnalyzer(analyzer, phrase);
  23. }
  24. /**
  25. * 标准分词器分词 ,中文会被切分为单字
  26. *
  27. * @param phrase
  28. * @return
  29. */
  30. public static List<String> segmentPhraseByStandardAnalyzer(String phrase) {
  31. Analyzer analyzer = new StandardAnalyzer();
  32. return segmentPhraseByAnalyzer(analyzer, phrase);
  33. }
  34. /**
  35. * 指定分词器分词
  36. *
  37. * @param analyzer
  38. * @param phrase
  39. * @return
  40. */
  41. public static List<String> segmentPhraseByAnalyzer(Analyzer analyzer, String phrase) {
  42. // 获取Lucene的TokenStream对象
  43. TokenStream ts = null;
  44. //最终返回的分词结果
  45. List<String> terms = new ArrayList<>();
  46. try {
  47. ts = analyzer.tokenStream("keywords", new StringReader(phrase));
  48. // 获取词元位置属性
  49. OffsetAttribute offset = ts.addAttribute(OffsetAttribute.class);
  50. // 获取词元文本属性
  51. CharTermAttribute term = ts.addAttribute(CharTermAttribute.class);
  52. // 获取词元文本属性
  53. TypeAttribute type = ts.addAttribute(TypeAttribute.class);
  54. // 重置TokenStream(重置StringReader)
  55. ts.reset();
  56. // 迭代获取分词结果
  57. while (ts.incrementToken()) {
  58. log.debug(offset.startOffset() + " - " + offset.endOffset() + " : " + term.toString() + " | " + type.type());
  59. // System.out.println(offset.startOffset() + " - " + offset.endOffset() + " : " + term.toString() + " | " + type.type());
  60. //放入词
  61. terms.add(term.toString());
  62. }
  63. // 关闭TokenStream(关闭StringReader)
  64. ts.end();
  65. } catch (Exception e) {
  66. log.error(e.getLocalizedMessage(), e);
  67. return new ArrayList<>();
  68. } finally {
  69. // 释放TokenStream的所有资源
  70. if (ts != null) {
  71. try {
  72. ts.close();
  73. } catch (IOException e) {
  74. log.error(e.getLocalizedMessage(), e);
  75. }
  76. }
  77. }
  78. //放入该短语
  79. // terms.add(phrase);
  80. return terms;
  81. }
  82. }
  1. /**
  2. * 查询条件封装
  3. * @param form
  4. * @return
  5. */
  6. private SearchSourceBuilder searchMallEsCondition(MallEsSearchFormDTO form) {
  7. BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
  8. SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
  9. // 关键词查询[商品名称/货品名称/品牌名称]
  10. // if (StringUtils.isNotBlank(form.getKeywords())) {
  11. // List<String> analyzedWords = IkAnalzyerUtil.segmentPhraseByIk(form.getKeywords());
  12. // for (String word : analyzedWords) {
  13. // boolQuery.must(queryStringQuery(String.format("*%s*", word.trim())).field("goodsName").field("goodsInfoName"));
  14. // }
  15. // }
  16. if (StringUtils.isNotBlank(form.getKeywords())) {
  17. boolQuery.must(QueryBuilders.multiMatchQuery(form.getKeywords(),"goodsInfoName","goodsName").operator(Operator.AND));
  18. }
  19. // 指定货品编码参数组合查询
  20. // List<String> goodsInfoItemNos = form.getGoodsInfoItemNos();
  21. // if (!ListHelper.isObjectNullOrEmpty(goodsInfoItemNos) && goodsInfoItemNos.size() > 0) {
  22. // BoolQueryBuilder includeBoolQuery = QueryBuilders.boolQuery();
  23. // for (String goodsInfoItemNo : goodsInfoItemNos) {
  24. // BoolQueryBuilder inBoolQuery = QueryBuilders.boolQuery();
  25. // inBoolQuery.must(matchQuery("goodsInfoItemNo", goodsInfoItemNo));
  26. // includeBoolQuery.should(inBoolQuery);
  27. // }
  28. // boolQuery.must(includeBoolQuery);
  29. // }
  30. //商品名称模糊查询
  31. if (StringUtils.isNotEmpty(form.getGoodsName())) {
  32. //boolQuery.must(queryStringQuery(String.format("*%s*", form.getGoodsName())).field("goodsName"));
  33. boolQuery.must(queryStringQuery(String.format("\"*%s*\" OR *%s*", form.getGoodsName(), form.getGoodsName())).field("goodsName"));
  34. }
  35. //货品名称模糊查询
  36. if (StringUtils.isNotEmpty(form.getGoodsInfoName())) {
  37. //boolQuery.must(queryStringQuery(String.format("*%s*", form.getGoodsInfoName())).field("goodsInfoName"));
  38. boolQuery.must(queryStringQuery(String.format("\"*%s*\" OR *%s*", form.getGoodsInfoName(), form.getGoodsInfoName())).field("goodsInfoName"));
  39. }
  40. if (!StringHelper.isNullOrEmpty(form.getPromotionFlag())&&"1".equals(form.getPromotionFlag())){
  41. boolQuery.must(QueryBuilders.nestedQuery("marketingActivityList",QueryBuilders.existsQuery("marketingActivityList"), ScoreMode.None));
  42. searchSourceBuilder.sort("activityGoodsSort",SortOrder.ASC);
  43. }
  44. if (!StringHelper.isNullOrEmpty(form.getPromotionGrade())){
  45. boolQuery.must(QueryBuilders.nestedQuery("marketingActivityList",QueryBuilders.queryStringQuery(String.format("*%s*", form.getPromotionGrade())).field("marketingActivityList.marketJoinGrade"), ScoreMode.None));
  46. }
  47. if (!StringHelper.isNullOrEmpty(form.getShowChannel())){
  48. boolQuery.must(QueryBuilders.nestedQuery("marketingActivityList",QueryBuilders.queryStringQuery(String.format("*%s*", form.getShowChannel())).field("marketingActivityList.showChannel"), ScoreMode.None));
  49. }
  50. if (!StringHelper.isNullOrEmpty(form.getShowStock())&&"0".equals(form.getShowStock())){
  51. RangeQueryBuilder goodsInfoStock = rangeQuery("goodsInfoStock")
  52. .gt(0);
  53. boolQuery.must(goodsInfoStock);
  54. }
  55. /******查询是否上架商品********/
  56. if (StringUtil.isNotEmptyOrWhiteSpace(form.getGoodsInfoAdded())) {
  57. /****-1的时候表示全部****/
  58. if (!form.getGoodsInfoAdded().equals("-1")) {
  59. //默认查询是要在列表展示的
  60. if (form.getKeywords() != null) {
  61. // 搜索是否上架的商品
  62. boolQuery.must(QueryBuilders.termQuery("goodsInfoAdded", form.getGoodsInfoAdded()));
  63. } else {
  64. if (form.isShowList()) {
  65. // 搜索是否上架的商品
  66. boolQuery.must(QueryBuilders.termQuery("goodsInfoAdded", form.getGoodsInfoAdded()))
  67. // 是否列表显示
  68. .must(QueryBuilders.termQuery("showList", "1"));
  69. } else {
  70. // 搜索是否上架的商品
  71. boolQuery.must(QueryBuilders.termQuery("goodsInfoAdded", form.getGoodsInfoAdded()));
  72. }
  73. }
  74. }
  75. } else {
  76. //默认查询是要在列表展示的
  77. if (form.getKeywords() != null) {
  78. boolQuery.must(QueryBuilders.termQuery("goodsInfoAdded", "1"));
  79. } else {
  80. if (form.isShowList()) {
  81. // 搜索上架商品
  82. boolQuery.must(QueryBuilders.termQuery("goodsInfoAdded", "1"))
  83. // 是否列表显示
  84. .must(QueryBuilders.termQuery("showList", "1"));
  85. } else {
  86. // 搜索上架商品
  87. boolQuery.must(QueryBuilders.termQuery("goodsInfoAdded", "1"));
  88. }
  89. }
  90. }
  91. //灰度上架:0=否;1=是
  92. if (!StringUtil.isNotEmptyOrWhiteSpace(form.getAlpha())) {
  93. //未设置,默认不看灰度上架货品
  94. boolQuery.must(QueryBuilders.termQuery("alpha", "0"));
  95. } else {
  96. if (form.getAlpha().equals("1")) {
  97. //能看灰度发布商品,不加条件筛选
  98. } else {
  99. boolQuery.must(QueryBuilders.termQuery("alpha", "0"));
  100. }
  101. }
  102. //Spu展示标记
  103. if (StringUtil.isNotEmptyOrWhiteSpace(form.getDisplaySpuFlag())) {
  104. boolQuery.must(QueryBuilders.termQuery("displaySpuFlag", form.getDisplaySpuFlag()));
  105. }
  106. //查询品牌id
  107. if (null != form.getBrandId() && form.getBrandId() > 0L) {
  108. boolQuery.must(termQuery("brand.brandId", form.getBrandId()));
  109. }
  110. //分类id
  111. if (null != form.getCatId() && form.getCatId() > 0L) {
  112. boolQuery.must(termQuery("catId", form.getCatId()));
  113. }
  114. // 指定商品ID查询
  115. if (null != form.getGoodsId() && form.getGoodsId() > 0L) {
  116. boolQuery.must(termQuery("goodsId", form.getGoodsId()));
  117. }
  118. // 多个商品ID查询
  119. if (!ListHelper.isNullOrEmpty(form.getGoodsIds())) {
  120. boolQuery.must(QueryBuilders.termsQuery("goodsId", form.getGoodsIds()));
  121. }
  122. // 指定货品ID查询
  123. if (null != form.getGoodsInfoId() && form.getGoodsInfoId() > 0L) {
  124. boolQuery.must(termQuery("goodsInfoId", form.getGoodsInfoId()));
  125. }
  126. // 多个货品ID查询
  127. if (!ListHelper.isNullOrEmpty(form.getGoodsInfoIds())) {
  128. boolQuery.must(QueryBuilders.termsQuery("goodsInfoId", form.getGoodsInfoIds()));
  129. }
  130. // 指定货品编码查询
  131. if (StringUtils.isNotEmpty(form.getGoodsInfoItemNo())) {
  132. boolQuery.must(matchQuery("goodsInfoItemNo", form.getGoodsInfoItemNo()));
  133. }
  134. // 多个货号询
  135. if (!ListHelper.isNullOrEmpty(form.getGoodsInfoItemNos())) {
  136. boolQuery.must(QueryBuilders.termsQuery("goodsInfoItemNo", form.getGoodsInfoItemNos()));
  137. }
  138. // 指定商品编码查询
  139. if (StringUtils.isNotEmpty(form.getGoodsNo())) {
  140. boolQuery.must(termQuery("goodsNo", form.getGoodsNo()));
  141. }
  142. // 多个商品编码
  143. if (!ListHelper.isNullOrEmpty(form.getGoodsNos())) {
  144. boolQuery.must(QueryBuilders.termsQuery("goodsNo", form.getGoodsNos()));
  145. }
  146. // 分类查询
  147. if (ArrayUtils.isNotEmpty(form.getCids()) && form.isVisitGcpt()) {
  148. BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
  149. boolQueryBuilder.must(QueryBuilders.termsQuery("cateList.id", form.getCids()));
  150. NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("cateList", boolQueryBuilder, ScoreMode.None);
  151. boolQuery.must(nestedQueryBuilder);
  152. }
  153. //剔除生产配套分类
  154. if (ArrayUtils.isNotEmpty(form.getCids()) && !form.isVisitGcpt()) {
  155. BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
  156. boolQueryBuilder.mustNot(QueryBuilders.termsQuery("cateList.id", form.getCids()));
  157. NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("cateList", boolQueryBuilder, ScoreMode.None);
  158. boolQuery.must(nestedQueryBuilder);
  159. }
  160. // 品牌查询
  161. if (ArrayUtils.isNotEmpty(form.getBrands())) {
  162. BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
  163. boolQueryBuilder.must(QueryBuilders.termsQuery("brand.brandName", form.getBrands()));
  164. NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("brand", boolQueryBuilder, ScoreMode.None);
  165. boolQuery.must(nestedQueryBuilder);
  166. }
  167. // 扩展参数
  168. if (ArrayUtils.isNotEmpty(form.getParams())) {
  169. for (String param : form.getParams()) {
  170. String[] paramArr = param.split(":");
  171. if ("价格".equals(paramArr[0]) && paramArr.length > 1 && StringUtils.isNotEmpty(paramArr[1])) {
  172. long[] prices = Arrays.stream(paramArr[1].split("-")).mapToLong(a -> {
  173. try {
  174. return Long.parseLong(a);
  175. } catch (Exception e) {
  176. log.error("商品根据价格查询出现异常", e);
  177. return 0L;
  178. }
  179. }).toArray();
  180. RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("goodsInfoPreferPrice");
  181. rangeQuery.gte(prices[0]);
  182. rangeQuery.lte(prices.length > 1 ? prices[1] : 0);
  183. boolQuery.filter(rangeQuery);
  184. } else {
  185. BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
  186. boolQueryBuilder.must(QueryBuilders.termQuery("paramList.attributeName", paramArr[0]));
  187. boolQueryBuilder.must(QueryBuilders.termQuery("paramList.attributeValue", paramArr[1]));
  188. NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("paramList", boolQueryBuilder, ScoreMode.None);
  189. boolQuery.must(nestedQueryBuilder);
  190. }
  191. }
  192. }
  193. // 只显示有货
  194. if (Objects.nonNull(form.getShowStock()) && "0".equals(form.getShowStock())) {
  195. // searchRequest.addFilter(FilterBuilders.scriptFilter(filter_script)
  196. // .addParam(CHECKWARE, Objects.isNull(form.getWareIds()) ? null : form.getWareIds()[0]));
  197. }
  198. if (form.getGroupGoodsId()){
  199. CollapseBuilder collapseBuilder = new CollapseBuilder("goodsId");
  200. searchSourceBuilder.collapse(collapseBuilder);
  201. }
  202. // 排序
  203. if (StringUtils.isNotBlank(form.getSort())) {
  204. switch (form.getSort()) {
  205. // 价格升序
  206. case "11D":
  207. // Script script = new Script(sort_script);
  208. // ScriptSortBuilder scriptSortBuilder = SortBuilders.scriptSort(script, ScriptSortBuilder.ScriptSortType.NUMBER).order(SortOrder.ASC);
  209. // searchSourceBuilder.sort(scriptSortBuilder);
  210. searchSourceBuilder.sort("goodsInfoMarketPrice",SortOrder.ASC);
  211. break;
  212. // 价格降序
  213. case "1D":
  214. searchSourceBuilder.sort("goodsInfoMarketPrice",SortOrder.DESC);
  215. break;
  216. // 销量降序
  217. case "2D":
  218. //默认过滤售罄的货品,三大专区,热销
  219. BoolQueryBuilder includeBoolQuery = QueryBuilders.boolQuery();
  220. //库存大于0
  221. RangeQueryBuilder goodsInfoStock = rangeQuery("goodsInfoStock")
  222. .gt(0);
  223. //允许超卖
  224. includeBoolQuery.should(QueryBuilders.termQuery("overSold", "1"));
  225. includeBoolQuery.should(goodsInfoStock);
  226. boolQuery.must(includeBoolQuery);
  227. searchSourceBuilder.sort("mallSales", SortOrder.DESC);
  228. searchSourceBuilder.sort("goodsInfoAddedTime",SortOrder.DESC);
  229. break;
  230. // 销量升序
  231. case "22D":
  232. searchSourceBuilder.sort("mallSales", SortOrder.ASC);
  233. searchSourceBuilder.sort("goodsInfoAddedTime",SortOrder.ASC);
  234. break;
  235. // 创建时间升序
  236. case "33D":
  237. searchSourceBuilder.sort("createDate", SortOrder.ASC);
  238. break;
  239. // 创建时间降序
  240. case "3D":
  241. searchSourceBuilder.sort("createDate", SortOrder.DESC);
  242. // searchRequest.addSort(new ScriptSortBuilder(date_sort_script, "number")
  243. // .order(SortOrder.DESC));
  244. // searchRequest.addSort(new ScriptSortBuilder(stock_sort_script, "number")
  245. // .order(SortOrder.DESC));
  246. break;
  247. // 收藏升序
  248. case "44D":
  249. // searchRequest.addSort("collectionCount", SortOrder.ASC);
  250. break;
  251. // 收藏降序
  252. case "4D":
  253. // searchRequest.addSort("collectionCount", SortOrder.DESC);
  254. break;
  255. // 上架时间升序
  256. case "55D":
  257. searchSourceBuilder.sort("goodsInfoAddedTime",SortOrder.ASC);
  258. break;
  259. // 上架时间降序
  260. case "5D":
  261. searchSourceBuilder.sort("goodsInfoAddedTime",SortOrder.DESC);
  262. break;
  263. // 评论数升序
  264. case "66D":
  265. // searchRequest.addSort("comment.commentCount", SortOrder.ASC);
  266. break;
  267. // 评论数降序
  268. case "6D":
  269. // searchRequest.addSort("comment.commentCount", SortOrder.DESC);
  270. break;
  271. case "7D":
  272. String marketJoinGrade = getMarketJoinGrade(form.getPriceGradeId());
  273. //按照促销活动排序
  274. if (!StringHelper.isNullOrEmpty(marketJoinGrade)){
  275. Map<String, Object> params = new HashMap<>();
  276. params.put("zero",0);
  277. params.put("one",1);
  278. params.put("nullCode",null);
  279. params.put("emptyStr","");
  280. params.put("marketJoinGrade",marketJoinGrade);
  281. Script marketJoinGradeScript = new Script(ScriptType.INLINE,"painless",marketing_sort,params);
  282. ScriptSortBuilder gradeScriptSortBuilder = SortBuilders.scriptSort(marketJoinGradeScript, ScriptSortBuilder.ScriptSortType.NUMBER).order(SortOrder.DESC);
  283. searchSourceBuilder.sort(gradeScriptSortBuilder);
  284. }else {
  285. Map<String, Object> params = new HashMap<>();
  286. params.put("zero",0);
  287. params.put("one",1);
  288. params.put("marketJoinGrade",marketJoinGrade);
  289. params.put("nullCode",null);
  290. params.put("emptyStr","");
  291. Script marketJoinGradeScript = new Script(ScriptType.INLINE,"painless",no_login_marketing_sort,params);
  292. ScriptSortBuilder gradeScriptSortBuilder = SortBuilders.scriptSort(marketJoinGradeScript, ScriptSortBuilder.ScriptSortType.NUMBER).order(SortOrder.DESC);
  293. searchSourceBuilder.sort(gradeScriptSortBuilder);
  294. }
  295. //按照商品名称带关键字货品
  296. searchSourceBuilder.sort("weight",SortOrder.DESC);
  297. //按照库存排序
  298. Map<String, Object> stockParams = new HashMap<>();
  299. stockParams.put("zero",0);
  300. stockParams.put("minusOne",-1);
  301. stockParams.put("zeroStr","0");
  302. stockParams.put("oneStr","1");
  303. Script stockScript = new Script(ScriptType.INLINE, "painless", stock_sort, stockParams);
  304. ScriptSortBuilder stockOrder = SortBuilders.scriptSort(stockScript, ScriptSortBuilder.ScriptSortType.NUMBER).order(SortOrder.DESC);
  305. searchSourceBuilder.sort(stockOrder);
  306. // searchSourceBuilder.sort("cat1Sort",SortOrder.ASC);
  307. // searchSourceBuilder.sort("cat2Sort",SortOrder.ASC);
  308. // searchSourceBuilder.sort("cat3Sort",SortOrder.ASC);
  309. searchSourceBuilder.sort("goodsInfoAddedTime",SortOrder.DESC);
  310. break;
  311. //根据价格升序
  312. case "88D":{
  313. /* if (StringHelper.isNullOrEmpty(form.getPriceGradeId())){
  314. break;
  315. }
  316. String sortField = getPriceLevel(form.getPriceGradeId());
  317. Script script2 = new Script("def price=_source."+sortField+"; if(price<0){return 0;}else{return price;}");
  318. ScriptSortBuilder scriptSortBuilder2 = SortBuilders.scriptSort(script2, ScriptSortBuilder.ScriptSortType.NUMBER).order(SortOrder.ASC);
  319. searchSourceBuilder.sort(scriptSortBuilder2);*/
  320. searchSourceBuilder.sort("goodsInfoMarketPrice",SortOrder.ASC);
  321. }
  322. break;
  323. //根据价格降序
  324. case "8D": {
  325. /* if (StringHelper.isNullOrEmpty(form.getPriceGradeId())){
  326. break;
  327. }
  328. String sortField = getPriceLevel(form.getPriceGradeId());
  329. Script script3 = new Script("def price=_source."+sortField+"; if(price<0){return 0;}else{return price;}");
  330. ScriptSortBuilder scriptSortBuilder3 = SortBuilders.scriptSort(script3, ScriptSortBuilder.ScriptSortType.NUMBER).order(SortOrder.DESC);
  331. searchSourceBuilder.sort(scriptSortBuilder3);*/
  332. searchSourceBuilder.sort("goodsInfoMarketPrice",SortOrder.DESC);
  333. }
  334. break;
  335. default:
  336. break;
  337. }
  338. }
  339. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  340. if(form.getGoodsInfoAddedTimeSort() != null && form.getGoodsInfoAddedTimeSort() == 0){
  341. boolQuery.must(termQuery("goodsInfoAdded", "1"));
  342. searchSourceBuilder.sort(sdf.format(form.getGoodsInfoAddedTime()),SortOrder.DESC);
  343. }else if(form.getGoodsInfoAddedTimeSort() != null && form.getGoodsInfoAddedTimeSort() == 1){
  344. boolQuery.must(termQuery("goodsInfoAdded", "1"));
  345. searchSourceBuilder.sort(sdf.format(form.getGoodsInfoAddedTime()),SortOrder.ASC);
  346. }
  347. searchSourceBuilder.query(boolQuery);
  348. AggregationBuilder aggregation =
  349. AggregationBuilders.nested("paramList","paramList")
  350. .subAggregation(AggregationBuilders.terms("attributeName")
  351. .field("paramList.attributeName").size(Integer.MAX_VALUE)
  352. .subAggregation(AggregationBuilders.terms("attributeValue").field("paramList.attributeValue"))
  353. );
  354. AggregationBuilder aggregation2 =
  355. AggregationBuilders.nested("brand","brand")
  356. .subAggregation(AggregationBuilders.terms("brandName").field("brand.brandName").size(Integer.MAX_VALUE)
  357. .subAggregation(AggregationBuilders.terms("brandLogo").field("brand.brandLogo"))
  358. );
  359. searchSourceBuilder.aggregation(aggregation);
  360. searchSourceBuilder.aggregation(aggregation2);
  361. searchSourceBuilder.from((form.getPageNo() - 1) * form.getPageSize()).size(form.getPageSize());
  362. return searchSourceBuilder;
  363. }
  1. /**
  2. * 处理聚合数据,并且过滤掉已选的参数
  3. *
  4. * @param resultMap
  5. * @param aggResult
  6. * @param brandArr 已选的品牌
  7. * @param paramArr 已选的扩展参数
  8. */
  9. private void processAggResult(Map<String, Object> resultMap, Object aggResult, String[] brandArr, String[] paramArr) {
  10. if (null == aggResult) {
  11. return;
  12. }
  13. // 将聚合结果转化为可操作的json对象
  14. JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(aggResult));
  15. // 处理扩展参数
  16. if (jsonObject.containsKey(PARAMLIST)) {
  17. List<com.swj.api.zagoods.service.searchplatform.vo.ExpandParamVo> paramVoList = new ArrayList<>();
  18. Object params = jsonObject.get(PARAMLIST);
  19. JSONArray paramArray;
  20. if (params instanceof JSONArray) {
  21. // 转化为jsonArray
  22. paramArray = (JSONArray) params;
  23. } else {
  24. //只有一个param,构造array
  25. paramArray = new JSONArray(Arrays.asList((Object) params));
  26. }
  27. for (Iterator<?> ite = paramArray.iterator(); ite.hasNext(); ) {
  28. Object paramObj = ite.next();
  29. if (paramObj instanceof JSONObject) {
  30. JSONObject paramJson = (JSONObject) paramObj;
  31. for (Map.Entry<String, Object> entry : paramJson.entrySet()) {
  32. // 判断当前的扩展参数是否与已选的相同
  33. boolean selected = false;
  34. if (paramArr != null && paramArr.length > 0) {
  35. for (String paramSelected : paramArr) {
  36. if (paramSelected.split(":")[0].equals(entry.getKey())) {
  37. selected = true;
  38. break;
  39. }
  40. }
  41. }
  42. // 未选中,则放入聚合结果
  43. if (!selected) {
  44. com.swj.api.zagoods.service.searchplatform.vo.ExpandParamVo paramVo = new com.swj.api.zagoods.service.searchplatform.vo.ExpandParamVo(entry.getKey());
  45. if (entry.getValue() instanceof List) {
  46. List<String> paramValues = (List<String>) entry.getValue();
  47. for (String paramValue : paramValues) {
  48. paramVo.addParamValue(new com.swj.api.zagoods.service.searchplatform.vo.ParamValueVo(paramValue));
  49. }
  50. } else {
  51. paramVo.addParamValue(new com.swj.api.zagoods.service.searchplatform.vo.ParamValueVo(entry.getValue().toString()));
  52. }
  53. //根据double值对扩展参数值数组进行排序
  54. sortParamValWithDoubleVal(paramVo);
  55. paramVoList.add(paramVo);
  56. }
  57. }
  58. }
  59. }
  60. resultMap.put("params", paramVoList);
  61. }
  62. // 处理品牌
  63. if (jsonObject.containsKey(BRAND)) {
  64. List<com.swj.api.zagoods.service.searchplatform.vo.BrandVo> brandVoList = new ArrayList<>();
  65. // 获取品牌信息
  66. Object brandObj = jsonObject.get(BRAND);
  67. // 已选择的品牌转换为列表
  68. List<String> brandList;
  69. if (brandArr == null || brandArr.length == 0) {
  70. brandList = new ArrayList<>();
  71. } else {
  72. brandList = Arrays.asList(brandArr);
  73. }
  74. if (brandObj instanceof JSONArray) {
  75. JSONArray brands = (JSONArray) brandObj;
  76. for (Object branObj : brands.toArray()) {
  77. JSONObject jsonObj = (JSONObject) branObj;
  78. for (Map.Entry<String, Object> entry : jsonObj.entrySet()) {
  79. if (entry.getKey() != null && !brandList.contains(String.valueOf(entry.getKey()))) {
  80. brandVoList.add(new com.swj.api.zagoods.service.searchplatform.vo.BrandVo(String.valueOf(entry.getKey()), String.valueOf(entry.getValue())));
  81. }
  82. }
  83. }
  84. } else if (brandObj instanceof JSONObject) {
  85. JSONObject brand = (JSONObject) brandObj;
  86. for (Map.Entry<String, Object> entry : brand.entrySet()) {
  87. if (entry.getKey() != null && !brandList.contains(String.valueOf(entry.getKey()))) {
  88. brandVoList.add(new com.swj.api.zagoods.service.searchplatform.vo.BrandVo(String.valueOf(entry.getKey()), String.valueOf(entry.getValue())));
  89. }
  90. }
  91. } else {
  92. if (!brandList.contains(brandObj.toString())) {
  93. brandVoList.add(new com.swj.api.zagoods.service.searchplatform.vo.BrandVo(brandObj.toString()));
  94. }
  95. }
  96. resultMap.put("brands", brandVoList);
  97. }
  98. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/68060
推荐阅读
相关标签
  

闽ICP备14008679号