1 package com.koolearn.framework.search.implement;
2
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.HashMap;
7 import java.util.Iterator;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Map.Entry;
11 import java.util.regex.Pattern;
12 import org.apache.commons.collections.CollectionUtils;
13 import org.apache.log4j.Logger;
14 import org.elasticsearch.action.bulk.BulkRequestBuilder;
15 import org.elasticsearch.action.bulk.BulkResponse;
16 import org.elasticsearch.action.search.SearchRequestBuilder;
17 import org.elasticsearch.action.search.SearchResponse;
18 import org.elasticsearch.action.search.SearchType;
19 import org.elasticsearch.action.suggest.SuggestResponse;
20 import org.elasticsearch.client.Client;
21 import org.elasticsearch.client.action.suggest.SuggestRequestBuilder;
22 import org.elasticsearch.client.transport.TransportClient;
23 import org.elasticsearch.common.Nullable;
24 import org.elasticsearch.common.settings.ImmutableSettings;
25 import org.elasticsearch.common.settings.Settings;
26 import org.elasticsearch.common.transport.InetSocketTransportAddress;
27 import org.elasticsearch.common.xcontent.XContentBuilder;
28 import org.elasticsearch.common.xcontent.XContentFactory;
29 import org.elasticsearch.index.query.AndFilterBuilder;
30 import org.elasticsearch.index.query.BoolQueryBuilder;
31 import org.elasticsearch.index.query.ExistsFilterBuilder;
32 import org.elasticsearch.index.query.FilterBuilders;
33 import org.elasticsearch.index.query.NotFilterBuilder;
34 import org.elasticsearch.index.query.QueryBuilder;
35 import org.elasticsearch.index.query.QueryBuilders;
36 import org.elasticsearch.index.query.QueryFilterBuilder;
37 import org.elasticsearch.index.query.QueryStringQueryBuilder;
38 import org.elasticsearch.index.query.RangeQueryBuilder;
39 import org.elasticsearch.search.SearchHit;
40 import org.elasticsearch.search.facet.FacetBuilders;
41 import org.elasticsearch.search.facet.terms.TermsFacet;
42 import org.elasticsearch.search.facet.terms.TermsFacetBuilder;
43 import org.elasticsearch.search.highlight.HighlightField;
44 import org.springframework.beans.factory.DisposableBean;
45 import org.springframework.beans.factory.InitializingBean;
46 import com.koolearn.framework.common.utils.PropertiesConfigUtils;
47 import com.koolearn.framework.search.declare.MySearchOption;
48 import com.koolearn.framework.search.declare.MySearchOption.DataFilter;
49 import com.koolearn.framework.search.declare.MySearchOption.SearchLogic;
50 import com.koolearn.framework.search.declare.SearchService;
51
52 public class SearchServiceImp implements SearchService, InitializingBean, DisposableBean {
53 private List<String> clusterList = null;
54 private Logger logger = Logger.getLogger(SearchServiceImp.class);
55 private Client searchClient = null;
56 private HashMap<String, String> searchClientConfigureMap = null;
57 private String highlightCSS = "";
58
59 public void setHighlightCSS(String highlightCSS) {
60 this.highlightCSS = highlightCSS;
61 }
62
63 public void setSearchClientConfigureMap(HashMap<String, String> searchClientConfigureMap) {
64 this.searchClientConfigureMap = searchClientConfigureMap;
65 }
66
67 private boolean _bulkInsertData(String indexName, XContentBuilder xContentBuilder) {
68 try {
69 BulkRequestBuilder bulkRequest = this.searchClient.prepareBulk();
70 bulkRequest.add(this.searchClient.prepareIndex(indexName, indexName).setSource(xContentBuilder));
71 BulkResponse bulkResponse = bulkRequest.execute().actionGet();
72 if (!bulkResponse.hasFailures()) {
73 return true;
74 }
75 else {
76 this.logger.error(bulkResponse.buildFailureMessage());
77 }
78 }
79 catch (Exception e) {
80 this.logger.error(e.getMessage());
81 }
82 return false;
83 }
84
85 public void afterPropertiesSet() throws Exception {
86 this.logger.info("连接搜索服务器");
87 this.open();
88 }
89
90 public boolean bulkDeleteData(String indexName, HashMap<String, Object[]> contentMap) {
91 try {
92 QueryBuilder queryBuilder = null;
93 queryBuilder = this.createQueryBuilder(contentMap, SearchLogic.must);
94 this.logger.warn("[" + indexName + "]" + queryBuilder.toString());
95 this.searchClient.prepareDeleteByQuery(indexName).setQuery(queryBuilder).execute().actionGet();
96 return true;
97 }
98 catch (Exception e) {
99 this.logger.error(e.getMessage());
100 }
101 return false;
102 }
103
104 public boolean bulkInsertData(String indexName, HashMap<String, Object[]> insertContentMap) {
105 XContentBuilder xContentBuilder = null;
106 try {
107 xContentBuilder = XContentFactory.jsonBuilder().startObject();
108 }
109 catch (IOException e) {
110 this.logger.error(e.getMessage());
111 return false;
112 }
113 Iterator<Entry<String, Object[]>> iterator = insertContentMap.entrySet().iterator();
114 while (iterator.hasNext()) {
115 Entry<String, Object[]> entry = iterator.next();
116 String field = entry.getKey();
117 Object[] values = entry.getValue();
118 String formatValue = this.formatInsertData(values);
119 try {
120 xContentBuilder = xContentBuilder.field(field, formatValue);
121 }
122 catch (IOException e) {
123 this.logger.error(e.getMessage());
124 return false;
125 }
126 }
127 try {
128 xContentBuilder = xContentBuilder.endObject();
129 }
130 catch (IOException e) {
131 this.logger.error(e.getMessage());
132 return false;
133 }
134 try {
135 this.logger.debug("[" + indexName + "]" + xContentBuilder.string());
136 }
137 catch (IOException e) {
138 this.logger.error(e.getMessage());
139 }
140 return this._bulkInsertData(indexName, xContentBuilder);
141 }
142
143 public boolean bulkUpdateData(String indexName, HashMap<String, Object[]> oldContentMap, HashMap<String, Object[]> newContentMap) {
144 if (this.bulkDeleteData(indexName, oldContentMap)) {
145 return this.bulkInsertData(indexName, newContentMap);
146 }
147 this.logger.warn("删除数据失败");
148 return false;
149 }
150
151 public boolean autoBulkUpdateData(String indexName, HashMap<String, Object[]> oldContentMap, HashMap<String, Object[]> newContentMap) {
152 try {
153 List<Map<String, Object>> searchResult = this.simpleSearch(new String[] { indexName }, oldContentMap, null, 0, 1, null, null);
154 if (searchResult == null || searchResult.size() == 0) {
155 this.logger.warn("未找到需要更新的数据");
156 return false;
157 }
158 if (!this.bulkDeleteData(indexName, oldContentMap)) {
159 this.logger.warn("删除数据失败");
160 return false;
161 }
162 HashMap<String, Object[]> insertContentMap = new HashMap<String, Object[]>();
163 for (Map<String, Object> contentMap : searchResult) {
164 Iterator<Entry<String, Object>> oldContentIterator = contentMap.entrySet().iterator();
165 while (oldContentIterator.hasNext()) {
166 Entry<String, Object> entry = oldContentIterator.next();
167 insertContentMap.put(entry.getKey(), new Object[] { entry.getValue() });
168 }
169 }
170 Iterator<Entry<String, Object[]>> newContentIterator = newContentMap.entrySet().iterator();
171 while (newContentIterator.hasNext()) {
172 Entry<String, Object[]> entry = newContentIterator.next();
173 insertContentMap.put(entry.getKey(), entry.getValue());
174 }
175 return this.bulkInsertData(indexName, insertContentMap);
176 }
177 catch (Exception e) {
178 this.logger.error(e.getMessage());
179 }
180 return false;
181 }
182
183 /*简单的值校验*/
184 private boolean checkValue(Object[] values) {
185 if (values == null) {
186 return false;
187 }
188 else if (values.length == 0) {
189 return false;
190 }
191 else if (values[0] == null) {
192 return false;
193 }
194 else if (values[0].toString().trim().isEmpty()) {
195 return false;
196 }
197 return true;
198 }
199
200 private void close() {
201 if (this.searchClient == null) {
202 return;
203 }
204 this.searchClient.close();
205 this.searchClient = null;
206 }
207
208 private RangeQueryBuilder createRangeQueryBuilder(String field, Object[] values) {
209 if (values.length == 1 || values[1] == null || values[1].toString().trim().isEmpty()) {
210 this.logger.warn("[区间搜索]必须传递两个值,但是只传递了一个值,所以返回null");
211 return null;
212 }
213 boolean timeType = false;
214 if (MySearchOption.isDate(values[0])) {
215 if (MySearchOption.isDate(values[1])) {
216 timeType = true;
217 }
218 }
219 String begin = "", end = "";
220 if (timeType) {
221 /*
222 * 如果时间类型的区间搜索出现问题,有可能是数据类型导致的:
223 * (1)在监控页面(elasticsearch-head)中进行range搜索,看看什么结果,如果也搜索不出来,则:
224 * (2)请确定mapping中是date类型,格式化格式是yyyy-MM-dd HH:mm:ss
225 * (3)请确定索引里的值是类似2012-01-01 00:00:00的格式
226 * (4)如果是从数据库导出的数据,请确定数据库字段是char或者varchar类型,而不是date类型(此类型可能会有问题)
227 * */
228 begin = MySearchOption.formatDate(values[0]);
229 end = MySearchOption.formatDate(values[1]);
230 }
231 else {
232 begin = values[0].toString();
233 end = values[1].toString();
234 }
235 return QueryBuilders.rangeQuery(field).from(begin).to(end);
236 }
237
238 /*
239 * 创建过滤条件
240 * */
241 private QueryBuilder createFilterBuilder(SearchLogic searchLogic, QueryBuilder queryBuilder, HashMap<String, Object[]> searchContentMap, HashMap<String, Object[]> filterContentMap) throws Exception
242 {
243 try {
244 Iterator<Entry<String, Object[]>> iterator = searchContentMap.entrySet().iterator();
245 AndFilterBuilder andFilterBuilder = null;
246 while (iterator.hasNext()) {
247 Entry<String, Object[]> entry = iterator.next();
248 Object[] values = entry.getValue();
249 /*排除非法的搜索值*/
250 if (!this.checkValue(values)) {
251 continue;
252 }
253 MySearchOption mySearchOption = this.getSearchOption(values);
254 if (mySearchOption.getDataFilter() == DataFilter.exists) {
255 /*被搜索的条件必须有值*/
256 ExistsFilterBuilder existsFilterBuilder = FilterBuilders.existsFilter(entry.getKey());
257 if (andFilterBuilder == null) {
258 andFilterBuilder = FilterBuilders.andFilter(existsFilterBuilder);
259 }
260 else {
261 andFilterBuilder = andFilterBuilder.add(existsFilterBuilder);
262 }
263 }
264 }
265 if (filterContentMap == null || filterContentMap.isEmpty()) {
266 /*如果没有其它过滤条件,返回*/
267 return QueryBuilders.filteredQuery(queryBuilder, andFilterBuilder);
268 }
269 /*构造过滤条件*/
270 QueryFilterBuilder queryFilterBuilder = FilterBuilders.queryFilter(this.createQueryBuilder(filterContentMap, searchLogic));
271 /*构造not过滤条件,表示搜索结果不包含这些内容,而不是不过滤*/
272 NotFilterBuilder notFilterBuilder = FilterBuilders.notFilter(queryFilterBuilder);
273 return QueryBuilders.filteredQuery(queryBuilder, FilterBuilders.andFilter(andFilterBuilder, notFilterBuilder));
274 }
275 catch (Exception e) {
276 this.logger.error(e.getMessage());
277 }
278 return null;
279 }
280
281 private QueryBuilder createSingleFieldQueryBuilder(String field, Object[] values, MySearchOption mySearchOption) {
282 try {
283 if (mySearchOption.getSearchType() == com.koolearn.framework.search.declare.MySearchOption.SearchType.range) {
284 /*区间搜索*/
285 return this.createRangeQueryBuilder(field, values);
286 }
287 // String[] fieldArray = field.split(",");/*暂时不处理多字段[field1,field2,......]搜索情况*/
288 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
289 for (Object valueItem : values) {
290 if (valueItem instanceof MySearchOption) {
291 continue;
292 }
293 QueryBuilder queryBuilder = null;
294 String formatValue = valueItem.toString().trim().replace("*", "");//格式化搜索数据
295 if (mySearchOption.getSearchType() == com.koolearn.framework.search.declare.MySearchOption.SearchType.term) {
296 queryBuilder = QueryBuilders.termQuery(field, formatValue).boost(mySearchOption.getBoost());
297 }
298 else if (mySearchOption.getSearchType() == com.koolearn.framework.search.declare.MySearchOption.SearchType.querystring) {
299 if (formatValue.length() == 1) {
300 /*如果搜索长度为1的非数字的字符串,格式化为通配符搜索,暂时这样,以后有时间改成multifield搜索,就不需要通配符了*/
301 if (!Pattern.matches("[0-9]", formatValue)) {
302 formatValue = "*"+formatValue+"*";
303 }
304 }
305 QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryString(formatValue).minimumShouldMatch(mySearchOption.getQueryStringPrecision());
306 queryBuilder = queryStringQueryBuilder.field(field).boost(mySearchOption.getBoost());
307 }
308 if (mySearchOption.getSearchLogic() == SearchLogic.should) {
309 boolQueryBuilder = boolQueryBuilder.should(queryBuilder);
310 }
311 else {
312 boolQueryBuilder = boolQueryBuilder.must(queryBuilder);
313 }
314 }
315 return boolQueryBuilder;
316 }
317 catch (Exception e) {
318 this.logger.error(e.getMessage());
319 }
320 return null;
321 }
322
323 /*
324 * 创建搜索条件
325 * */
326 private QueryBuilder createQueryBuilder(HashMap<String, Object[]> searchContentMap, SearchLogic searchLogic) {
327 try {
328 if (searchContentMap == null || searchContentMap.size() ==0) {
329 return null;
330 }
331 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
332 Iterator<Entry<String, Object[]>> iterator = searchContentMap.entrySet().iterator();
333 /*循环每一个需要搜索的字段和值*/
334 while (iterator.hasNext()) {
335 Entry<String, Object[]> entry = iterator.next();
336 String field = entry.getKey();
337 Object[] values = entry.getValue();
338 /*排除非法的搜索值*/
339 if (!this.checkValue(values)) {
340 continue;
341 }
342 /*获得搜索类型*/
343 MySearchOption mySearchOption = this.getSearchOption(values);
344 QueryBuilder queryBuilder = this.createSingleFieldQueryBuilder(field, values, mySearchOption);
345 if (queryBuilder != null) {
346 if (searchLogic == SearchLogic.should) {
347 /*should关系,也就是说,在A索引里有或者在B索引里有都可以*/
348 boolQueryBuilder = boolQueryBuilder.should(queryBuilder);
349 }
350 else {
351 /*must关系,也就是说,在A索引里有,在B索引里也必须有*/
352 boolQueryBuilder = boolQueryBuilder.must(queryBuilder);
353 }
354 }
355 }
356 return boolQueryBuilder;
357 }
358 catch (Exception e) {
359 this.logger.error(e.getMessage());
360 }
361 return null;
362 }
363
364 public void destroy() throws Exception {
365 this.logger.info("关闭搜索客户端");
366 this.close();
367 }
368
369 private String formatInsertData(Object[] values) {
370 if (!this.checkValue(values)) {
371 return "";
372 }
373 if (MySearchOption.isDate(values[0])) {
374 this.logger.warn("[" + values[0].toString() + "] formatDate");
375 return MySearchOption.formatDate(values[0]);
376 }
377 String formatValue = values[0].toString();
378 for (int index = 1; index < values.length; ++index) {
379 formatValue += "," + values[index].toString();
380 }
381 return formatValue.trim();
382 }
383
384 public long getCount(String[] indexNames, HashMap<String, Object[]> searchContentMap, HashMap<String, Object[]> filterContentMap) {
385 SearchLogic searchLogic = indexNames.length > 1 ? SearchLogic.should : SearchLogic.must;
386 return this.getCount(indexNames, searchContentMap, searchLogic, filterContentMap, searchLogic);
387 }
388
389 private SearchResponse searchCountRequest(String[] indexNames, Object queryBuilder) {
390 try {
391 SearchRequestBuilder searchRequestBuilder = this.searchClient.prepareSearch(indexNames).setSearchType(SearchType.COUNT);
392 if (queryBuilder instanceof QueryBuilder) {
393 searchRequestBuilder = searchRequestBuilder.setQuery((QueryBuilder)queryBuilder);
394 this.logger.debug(searchRequestBuilder.toString());
395 }
396 if (queryBuilder instanceof byte[]) {
397 String query = new String((byte[])queryBuilder);
398 searchRequestBuilder = searchRequestBuilder.setQuery(QueryBuilders.wrapperQuery(query));
399 this.logger.debug(query);
400 }
401 return searchRequestBuilder.execute().actionGet();
402 }
403 catch (Exception e) {
404 this.logger.error(e.getMessage());
405 }
406 return null;
407 }
408
409 public long getCount(String[] indexNames, byte[] queryString) {
410 try {
411 SearchResponse searchResponse = this.searchCountRequest(indexNames, queryString);
412 return searchResponse.hits().totalHits();
413 }
414 catch (Exception e) {
415 this.logger.error(e.getMessage());
416 }
417 return 0;
418 }
419
420 /*获得搜索结果*/
421 private List<Map<String, Object>> getSearchResult(SearchResponse searchResponse) {
422 try {
423 List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
424 for (SearchHit searchHit : searchResponse.getHits()) {
425 Iterator<Entry<String, Object>> iterator = searchHit.getSource().entrySet().iterator();
426 HashMap<String, Object> resultMap = new HashMap<String, Object>();
427 while (iterator.hasNext()) {
428 Entry<String, Object> entry = iterator.next();
429 resultMap.put(entry.getKey(), entry.getValue());
430 }
431 Map<String, HighlightField> highlightMap = searchHit.highlightFields();
432 Iterator<Entry<String, HighlightField>> highlightIterator = highlightMap.entrySet().iterator();
433 while (highlightIterator.hasNext()) {
434 Entry<String, HighlightField> entry = highlightIterator.next();
435 Object[] contents = entry.getValue().fragments();
436 if (contents.length == 1) {
437 resultMap.put(entry.getKey(), contents[0].toString());
438 System.out.println(contents[0].toString());
439 }
440 else {
441 this.logger.warn("搜索结果中的高亮结果出现多数据contents.length = " + contents.length);
442 }
443 }
444 resultList.add(resultMap);
445 }
446 return resultList;
447 }
448 catch (Exception e) {
449 this.logger.error(e.getMessage());
450 }
451 return null;
452 }
453
454 /*获得搜索选项*/
455 private MySearchOption getSearchOption(Object[] values) {
456 try {
457 for (Object item : values) {
458 if (item instanceof MySearchOption) {
459 return (MySearchOption) item;
460 }
461 }
462 }
463 catch (Exception e) {
464 this.logger.error(e.getMessage());
465 }
466 return new MySearchOption();
467 }
468
469 /*获得搜索建议
470 * 服务器端安装elasticsearch-plugin-suggest
471 * 客户端加入elasticsearch-plugin-suggest的jar包
472 * https://github.com/spinscale/elasticsearch-suggest-plugin
473 * */
474 public List<String> getSuggest(String[] indexNames, String fieldName, String value, int count) {
475 try {
476 SuggestRequestBuilder suggestRequestBuilder = new SuggestRequestBuilder(this.searchClient);
477 suggestRequestBuilder = suggestRequestBuilder.setIndices(indexNames).field(fieldName).term(value).size(count);//.similarity(0.5f);
478 SuggestResponse suggestResponse = suggestRequestBuilder.execute().actionGet();
479 return suggestResponse.suggestions();
480 }
481 catch (Exception e) {
482 this.logger.error(e.getMessage());
483 }
484 return null;
485 }
486
487 /*
488 * 创建搜索客户端
489 * tcp连接搜索服务器
490 * 创建索引
491 * 创建mapping
492 * */
493 private void open() {
494 try {
495 /*如果10秒没有连接上搜索服务器,则超时*/
496 Settings settings = ImmutableSettings.settingsBuilder()
497 .put(this.searchClientConfigureMap)
498 // .put("client.transport.ping_timeout", "10s")
499 // .put("client.transport.sniff", "true")
500 // .put("client.transport.ignore_cluster_name", "true")
501 .build();
502 /*创建搜索客户端*/
503 this.searchClient = new TransportClient(settings);
504 if (CollectionUtils.isEmpty(this.clusterList)) {
505 String cluster = PropertiesConfigUtils.getProperty("search.clusterList");
506 if (cluster != null) {
507 this.clusterList = Arrays.asList(cluster.split(","));
508 }
509 }
510 for (String item : this.clusterList) {
511 String address = item.split(":")[0];
512 int port = Integer.parseInt(item.split(":")[1]);
513 /*通过tcp连接搜索服务器,如果连接不上,有一种可能是服务器端与客户端的jar包版本不匹配*/
514 this.searchClient = ((TransportClient) this.searchClient).addTransportAddress(new InetSocketTransportAddress(address, port));
515 }
516 }
517 catch (Exception e) {
518 this.logger.error(e.getMessage());
519 }
520 }
521
522 public void setClusterList(List<String> clusterList) {
523 this.clusterList = clusterList;
524 }
525
526 public List<Map<String, Object>> simpleSearch(String[] indexNames, HashMap<String, Object[]> searchContentMap, HashMap<String, Object[]> filterContentMap, int from, int offset) {
527 return this.simpleSearch(indexNames, searchContentMap, filterContentMap, from, offset, null, null);
528 }
529
530 public List<Map<String, Object>> simpleSearch(String[] indexNames, HashMap<String, Object[]> searchContentMap, HashMap<String, Object[]> filterContentMap, int from, int offset, String sortField, String sortType)
531 {
532 SearchLogic searchLogic = indexNames.length > 1 ? SearchLogic.should : SearchLogic.must;
533 return this.simpleSearch(indexNames, searchContentMap, searchLogic, filterContentMap, searchLogic, from, offset, sortField, sortType);
534 }
535
536 public long getComplexCount(String[] indexNames
537 , HashMap<String, Object[]> mustSearchContentMap
538 , HashMap<String, Object[]> shouldSearchContentMap) {
539 /*创建must搜索条件*/
540 QueryBuilder mustQueryBuilder = this.createQueryBuilder(mustSearchContentMap, SearchLogic.must);
541 /*创建should搜索条件*/
542 QueryBuilder shouldQueryBuilder = this.createQueryBuilder(shouldSearchContentMap, SearchLogic.should);
543 if (mustQueryBuilder == null && shouldQueryBuilder == null) {
544 return 0;
545 }
546 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
547 if (mustQueryBuilder != null) {
548 boolQueryBuilder = boolQueryBuilder.must(mustQueryBuilder);
549 }
550 if (shouldQueryBuilder != null) {
551 boolQueryBuilder = boolQueryBuilder.must(shouldQueryBuilder);
552 }
553 try {
554 SearchResponse searchResponse = this.searchCountRequest(indexNames, boolQueryBuilder);
555 return searchResponse.hits().totalHits();
556 }
557 catch (Exception e) {
558 this.logger.error(e.getMessage());
559 }
560 return 0;
561 }
562
563 public List<Map<String, Object>> complexSearch(String[] indexNames
564 , HashMap<String, Object[]> mustSearchContentMap
565 , HashMap<String, Object[]> shouldSearchContentMap
566 , int from, int offset, @Nullable String sortField, @Nullable String sortType) {
567 if (offset <= 0) {
568 return null;
569 }
570 /*创建must搜索条件*/
571 QueryBuilder mustQueryBuilder = this.createQueryBuilder(mustSearchContentMap, SearchLogic.must);
572 /*创建should搜索条件*/
573 QueryBuilder shouldQueryBuilder = this.createQueryBuilder(shouldSearchContentMap, SearchLogic.should);
574 if (mustQueryBuilder == null && shouldQueryBuilder == null) {
575 return null;
576 }
577 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
578 if (mustQueryBuilder != null) {
579 boolQueryBuilder = boolQueryBuilder.must(mustQueryBuilder);
580 }
581 if (shouldQueryBuilder != null) {
582 boolQueryBuilder = boolQueryBuilder.must(shouldQueryBuilder);
583 }
584 try {
585 SearchRequestBuilder searchRequestBuilder = null;
586 searchRequestBuilder = this.searchClient.prepareSearch(indexNames).setSearchType(SearchType.DEFAULT)
587 .setQuery(boolQueryBuilder).setFrom(from).setSize(offset).setExplain(true);
588 if (sortField == null || sortField.isEmpty() || sortType == null || sortType.isEmpty()) {
589 /*如果不需要排序*/
590 }
591 else {
592 /*如果需要排序*/
593 org.elasticsearch.search.sort.SortOrder sortOrder = sortType.equals("desc") ? org.elasticsearch.search.sort.SortOrder.DESC : org.elasticsearch.search.sort.SortOrder.ASC;
594 searchRequestBuilder = searchRequestBuilder.addSort(sortField, sortOrder);
595 }
596 searchRequestBuilder = this.createHighlight(searchRequestBuilder, mustSearchContentMap);
597 searchRequestBuilder = this.createHighlight(searchRequestBuilder, shouldSearchContentMap);
598 this.logger.debug(searchRequestBuilder.toString());
599 SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
600 return this.getSearchResult(searchResponse);
601 }
602 catch (Exception e) {
603 this.logger.error(e.getMessage());
604 }
605 return null;
606 }
607
608 public List<Map<String, Object>> simpleSearch(String[] indexNames, byte[] queryString, int from, int offset, String sortField, String sortType) {
609 if (offset <= 0) {
610 return null;
611 }
612 try {
613 SearchRequestBuilder searchRequestBuilder = this.searchClient.prepareSearch(indexNames).setSearchType(SearchType.DEFAULT)
614 .setFrom(from).setSize(offset).setExplain(true);
615 if (sortField == null || sortField.isEmpty() || sortType == null || sortType.isEmpty()) {
616 /*如果不需要排序*/
617 }
618 else {
619 /*如果需要排序*/
620 org.elasticsearch.search.sort.SortOrder sortOrder = sortType.equals("desc") ? org.elasticsearch.search.sort.SortOrder.DESC : org.elasticsearch.search.sort.SortOrder.ASC;
621 searchRequestBuilder = searchRequestBuilder.addSort(sortField, sortOrder);
622 }
623
624 String query = new String(queryString);
625 searchRequestBuilder = searchRequestBuilder.setQuery(QueryBuilders.wrapperQuery(query));
626 this.logger.debug(query);
627
628 SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
629 return this.getSearchResult(searchResponse);
630 }
631 catch (Exception e) {
632 this.logger.error(e.getMessage());
633 }
634 return null;
635 }
636
637 private Map<String, String> _group(String indexName, QueryBuilder queryBuilder, String[] groupFields) {
638 try {
639 TermsFacetBuilder termsFacetBuilder = FacetBuilders.termsFacet("group").fields(groupFields).size(9999);
640 SearchRequestBuilder searchRequestBuilder = this.searchClient.prepareSearch(indexName).setSearchType(SearchType.DEFAULT)
641 .addFacet(termsFacetBuilder).setQuery(queryBuilder).setFrom(0).setSize(1).setExplain(true);
642 this.logger.debug(searchRequestBuilder.toString());
643 SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
644 TermsFacet termsFacet = searchResponse.getFacets().facet("group");
645 HashMap<String, String> result = new HashMap<String, String>();
646 for (org.elasticsearch.search.facet.terms.TermsFacet.Entry entry : termsFacet.entries()) {
647 result.put(entry.getTerm(), entry.count() + "");
648 }
649 return result;
650 }
651 catch (Exception e) {
652 this.logger.error(e.getMessage());
653 }
654 return null;
655 }
656
657 public Map<String, String> group(String indexName
658 , HashMap<String, Object[]> mustSearchContentMap
659 , HashMap<String, Object[]> shouldSearchContentMap
660 , String[] groupFields) {
661 /*创建must搜索条件*/
662 QueryBuilder mustQueryBuilder = this.createQueryBuilder(mustSearchContentMap, SearchLogic.must);
663 /*创建should搜索条件*/
664 QueryBuilder shouldQueryBuilder = this.createQueryBuilder(shouldSearchContentMap, SearchLogic.should);
665 if (mustQueryBuilder == null && shouldQueryBuilder == null) {
666 return null;
667 }
668 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
669 if (mustQueryBuilder != null) {
670 boolQueryBuilder = boolQueryBuilder.must(mustQueryBuilder);
671 }
672 if (shouldQueryBuilder != null) {
673 boolQueryBuilder = boolQueryBuilder.must(shouldQueryBuilder);
674 }
675 try {
676 return this._group(indexName, boolQueryBuilder, groupFields);
677 }
678 catch (Exception e) {
679 this.logger.error(e.getMessage());
680 }
681 return null;
682 }
683
684 public List<Map<String, Object>> simpleSearch(String[] indexNames
685 , HashMap<String, Object[]> searchContentMap, SearchLogic searchLogic
686 , HashMap<String, Object[]> filterContentMap, SearchLogic filterLogic
687 , int from, int offset, String sortField, String sortType)
688 {
689 if (offset <= 0) {
690 return null;
691 }
692 try {
693 QueryBuilder queryBuilder = null;
694 queryBuilder = this.createQueryBuilder(searchContentMap, searchLogic);
695 queryBuilder = this.createFilterBuilder(filterLogic, queryBuilder, searchContentMap, filterContentMap);
696 SearchRequestBuilder searchRequestBuilder = this.searchClient.prepareSearch(indexNames).setSearchType(SearchType.DEFAULT)
697 .setQuery(queryBuilder).setFrom(from).setSize(offset).setExplain(true);
698 if (sortField == null || sortField.isEmpty() || sortType == null || sortType.isEmpty()) {
699 /*如果不需要排序*/
700 }
701 else {
702 /*如果需要排序*/
703 org.elasticsearch.search.sort.SortOrder sortOrder = sortType.equals("desc") ? org.elasticsearch.search.sort.SortOrder.DESC : org.elasticsearch.search.sort.SortOrder.ASC;
704 searchRequestBuilder = searchRequestBuilder.addSort(sortField, sortOrder);
705 }
706 searchRequestBuilder = this.createHighlight(searchRequestBuilder, searchContentMap);
707 this.logger.debug(searchRequestBuilder.toString());
708 SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
709 return this.getSearchResult(searchResponse);
710 }
711 catch (Exception e) {
712 this.logger.error(e.getMessage());
713 }
714 return null;
715 }
716
717 private SearchRequestBuilder createHighlight(SearchRequestBuilder searchRequestBuilder, HashMap<String, Object[]> searchContentMap) {
718 Iterator<Entry<String, Object[]>> iterator = searchContentMap.entrySet().iterator();
719 /*循环每一个需要搜索的字段和值*/
720 while (iterator.hasNext()) {
721 Entry<String, Object[]> entry = iterator.next();
722 String field = entry.getKey();
723 Object[] values = entry.getValue();
724 /*排除非法的搜索值*/
725 if (!this.checkValue(values)) {
726 continue;
727 }
728 /*获得搜索类型*/
729 MySearchOption mySearchOption = this.getSearchOption(values);
730 if (mySearchOption.isHighlight()) {
731 /*
732 * http://www.elasticsearch.org/guide/reference/api/search/highlighting.html
733 *
734 * fragment_size设置成1000,默认值会造成返回的数据被截断
735 * */
736 searchRequestBuilder = searchRequestBuilder.addHighlightedField(field, 1000)
737 .setHighlighterPreTags("<"+this.highlightCSS.split(",")[0]+">")
738 .setHighlighterPostTags("</"+this.highlightCSS.split(",")[1]+">");
739 }
740 }
741 return searchRequestBuilder;
742 }
743
744 public long getCount(String[] indexNames
745 , HashMap<String, Object[]> searchContentMap, SearchLogic searchLogic
746 , @Nullable HashMap<String, Object[]> filterContentMap, @Nullable SearchLogic filterLogic)
747 {
748 QueryBuilder queryBuilder = null;
749 try {
750 queryBuilder = this.createQueryBuilder(searchContentMap, searchLogic);
751 queryBuilder = this.createFilterBuilder(searchLogic, queryBuilder, searchContentMap, filterContentMap);
752 SearchResponse searchResponse = this.searchCountRequest(indexNames, queryBuilder);
753 return searchResponse.hits().totalHits();
754 }
755 catch (Exception e) {
756 this.logger.error(e.getMessage());
757 }
758 return 0;
759 }
760 }