ES有多种查询方式,我自己的业务是需要对多个字段进行查询,具体实现类代码如下。
1 package com.cs99lzzs.elasticsearch.service.imp; 2 3 import java.text.DecimalFormat; 4 import java.util.ArrayList; 5 import java.util.Iterator; 6 import java.util.List; 7 import java.util.Map; 8 9 import javax.annotation.Resource; 10 11 import org.apache.commons.lang.StringUtils; 12 import org.apache.log4j.Logger; 13 import org.apache.lucene.queryparser.classic.QueryParser; 14 import org.elasticsearch.action.search.SearchRequestBuilder; 15 import org.elasticsearch.action.search.SearchResponse; 16 import org.elasticsearch.action.search.SearchType; 17 import org.elasticsearch.client.Client; 18 import org.elasticsearch.index.query.BoolQueryBuilder; 19 import org.elasticsearch.index.query.QueryBuilder; 20 import org.elasticsearch.index.query.QueryBuilders; 21 import org.elasticsearch.search.SearchHit; 22 import org.elasticsearch.search.aggregations.Aggregation; 23 import org.elasticsearch.search.aggregations.AggregationBuilders; 24 import org.elasticsearch.search.aggregations.bucket.terms.StringTerms; 25 import org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket; 26 import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; 27 import org.elasticsearch.search.sort.SortBuilder; 28 import org.elasticsearch.search.sort.SortBuilders; 29 import org.elasticsearch.search.sort.SortOrder; 30 import org.elasticsearch.search.suggest.Suggest; 31 import org.elasticsearch.search.suggest.SuggestBuilder; 32 import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder; 33 import org.springframework.beans.factory.annotation.Value; 34 import org.springframework.stereotype.Service; 35 36 import com.alibaba.fastjson.JSON; 37 import com.cs99lzzs.elasticsearch.service.ProductSearchService; 38 import com.cs99lzzs.search.ElasticseachSku; 39 import com.cs99lzzs.search.EsProductQuery; 40 import com.cs99lzzs.search.EsResultingSku; 41 import com.cs99lzzs.search.vo.FacetVO; 42 import com.cs99lzzs.search.vo.SearchResultVO; 43 44 @Service("productSearchService") 45 public class ProductSearchServiceImp implements ProductSearchService { 46 47 private static Logger logger = Logger.getLogger(ProductSearchService.class); 48 49 private static String aggrationBrandName = "brand_count"; 50 51 private static String suggestZhName = "suggestName"; 52 53 @Resource(name="esClient") 54 Client esClient; 55 56 @Value("${elasticsearch.index}") 57 private String CLUSTER_INDEX; 58 59 @Value("${elasticsearch.type}") 60 private String CLUSTER_TYPE; 61 62 63 /** 64 * @return 65 */ 66 @SuppressWarnings("rawtypes") 67 @Override 68 public SearchResultVO get(EsProductQuery esProductQuery) { 69 if (esProductQuery == null || 70 (StringUtils.isEmpty(esProductQuery.getKeyword()) 71 && StringUtils.isEmpty(esProductQuery.getCateName()) 72 && StringUtils.isEmpty(esProductQuery.getBrandName()))) { 73 return null; 74 } 75 //生成搜索条件 76 QueryBuilder boolQuery = generateBoolQuery(esProductQuery, null); 77 78 //浅度分页,越到后面,反应越慢,还有可能导致es崩溃 79 SearchRequestBuilder srb = esClient.prepareSearch(CLUSTER_INDEX) 80 .setTypes(CLUSTER_TYPE) 81 .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) 82 .setQuery(boolQuery) 83 // .setPostFilter(QueryBuilders.rangeQuery("age").from(12).to(18)) 84 .setExplain(true) //explain为true表示根据数据相关度排序,和关键字匹配最高的排在前面 85 .setFrom((esProductQuery.getPage() - 1) * esProductQuery.getPageSize()) 86 .setSize(esProductQuery.getPageSize()); 87 88 //获取排序规则 89 SortBuilder sortBuilder = getSortBuilder(esProductQuery); 90 if (sortBuilder != null) { 91 srb.addSort(sortBuilder); 92 } 93 94 //按品牌名聚合 95 TermsAggregationBuilder termAgg = AggregationBuilders.terms(aggrationBrandName).field("brandName"); 96 srb.addAggregation(termAgg); 97 98 //执行搜索 99 SearchResponse actionGet = srb.execute().actionGet(); 100 101 //深度分页,推荐实现 102 // SearchScrollRequestBuilder ssrb = esClient.prepareSearchScroll(actionGet.getScrollId()) 103 // .setScroll(TimeValue.timeValueMinutes(8)); 104 //获取查询结果,生成返回对象 105 List<EsResultingSku> skuList = new ArrayList<EsResultingSku>(); 106 DecimalFormat priceFormat = new DecimalFormat("#0.00"); 107 DecimalFormat discountFormat = new DecimalFormat("#0.0"); 108 109 SearchHit[] hitArray = actionGet.getHits().getHits(); 110 for (SearchHit searchHit : hitArray) { 111 ElasticseachSku eSku = JSON.parseObject(searchHit.getSourceAsString(), ElasticseachSku.class); 112 if (eSku != null) { 113 skuList.add(new EsResultingSku(eSku, discountFormat, priceFormat)); 114 } 115 } 116 117 SearchResultVO resultVO = new SearchResultVO(); 118 resultVO.setSkus(skuList); 119 //总页数 120 long totalPage = actionGet.getHits().totalHits/esProductQuery.getPageSize(); 121 if ((actionGet.getHits().totalHits % esProductQuery.getPageSize()) != 0) { 122 totalPage ++; 123 } 124 resultVO.setTotalPages(totalPage); 125 resultVO.setHits(actionGet.getHits().totalHits); 126 if (skuList.size() > 1) { 127 setFacetVOs(actionGet, resultVO); 128 } 129 130 return resultVO; 131 } 132 /** 133 * @return 134 */ 135 @Override 136 public SearchResultVO get(String keyword, int page, int pageSize) { 137 if (StringUtils.isEmpty(keyword)) { 138 return null; 139 } 140 141 //生成搜索条件 142 QueryBuilder boolQuery = generateBoolQuery(null, keyword); 143 144 //浅度分页,越到后面,反应越慢,还有可能导致es崩溃 145 SearchRequestBuilder srb = esClient.prepareSearch(CLUSTER_INDEX) 146 .setTypes(CLUSTER_TYPE) 147 .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) 148 .setQuery(boolQuery) 149 // .setPostFilter(QueryBuilders.rangeQuery("age").from(12).to(18)) 150 .setExplain(true) //explain为true表示根据数据相关度排序,和关键字匹配最高的排在前面 151 .setFrom((page - 1) * pageSize) 152 .setSize(pageSize); 153 154 //按品牌名聚合 155 TermsAggregationBuilder termAgg = AggregationBuilders.terms(aggrationBrandName).field("brandName"); 156 srb.addAggregation(termAgg); 157 158 //执行搜索 159 SearchResponse actionGet = srb.execute().actionGet(); 160 161 //深度分页,推荐实现 162 // SearchScrollRequestBuilder ssrb = esClient.prepareSearchScroll(actionGet.getScrollId()) 163 // .setScroll(TimeValue.timeValueMinutes(8)); 164 //获取查询结果,生成返回对象 165 List<EsResultingSku> skuList = new ArrayList<EsResultingSku>(); 166 DecimalFormat priceFormat = new DecimalFormat("#0.00"); 167 DecimalFormat discountFormat = new DecimalFormat("#0.0"); 168 169 SearchHit[] hitArray = actionGet.getHits().getHits(); 170 for (SearchHit searchHit : hitArray) { 171 ElasticseachSku eSku = JSON.parseObject(searchHit.getSourceAsString(), ElasticseachSku.class); 172 if (eSku != null) { 173 skuList.add(new EsResultingSku(eSku, discountFormat, priceFormat)); 174 } 175 } 176 177 SearchResultVO resultVO = new SearchResultVO(); 178 resultVO.setSkus(skuList); 179 //总页数 180 long totalPage = actionGet.getHits().totalHits/pageSize; 181 if ((actionGet.getHits().totalHits % pageSize) != 0) { 182 totalPage ++; 183 } 184 resultVO.setTotalPages(totalPage); 185 resultVO.setHits(actionGet.getHits().totalHits); 186 187 188 return resultVO; 189 } 190 191 /** 192 * @param esProductQuery 193 * @param keyword 194 * @return 195 */ 196 private QueryBuilder generateBoolQuery(EsProductQuery esProductQuery, String key) { 197 198 String keyword = null; 199 if (esProductQuery != null && esProductQuery.getKeyword() != null) { 200 keyword = QueryParser.escape(esProductQuery.getKeyword()); 201 } 202 if (StringUtils.isNotEmpty(key)) { 203 keyword = QueryParser.escape(key); 204 } 205 206 logger.info("filtered keyword is : " + keyword); 207 208 //其他搜索条件 209 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); 210 if (esProductQuery != null) { 211 if (esProductQuery.getIsDelete() == 1) { 212 boolQueryBuilder.must(QueryBuilders.termQuery("isDelete", true)); 213 } else if (esProductQuery.getIsDelete() == -1) { 214 boolQueryBuilder.must(QueryBuilders.termQuery("isDelete", false)); 215 } 216 if (esProductQuery.getSearchable() == 1) { 217 boolQueryBuilder.must(QueryBuilders.termQuery("searchable", true)); 218 } else if (esProductQuery.getIsDelete() == -1) { 219 boolQueryBuilder.must(QueryBuilders.termQuery("searchable", false)); 220 } 221 if (StringUtils.isNotEmpty(esProductQuery.getBrandName())) { 222 boolQueryBuilder.must(QueryBuilders.termQuery("brandName", QueryParser.escape(esProductQuery.getBrandName()))); 223 } 224 if (StringUtils.isNotEmpty(esProductQuery.getCateName())) { 225 boolQueryBuilder.must(QueryBuilders.termQuery("cateName", QueryParser.escape(esProductQuery.getCateName()))); 226 } 227 } else { 228 boolQueryBuilder.must(QueryBuilders.termQuery("isDelete", false)); 229 boolQueryBuilder.must(QueryBuilders.termQuery("searchable", true)); 230 } 231 232 QueryBuilder multiMatchQuery = null; 233 if (StringUtils.isNotEmpty(keyword)) { 234 multiMatchQuery = QueryBuilders.multiMatchQuery(keyword, 235 "enName", "zhName","brandZhName", "brandEnName", "aliases", "brandAliases"); 236 } 237 238 if (multiMatchQuery == null) { 239 return boolQueryBuilder; 240 } else { 241 return boolQueryBuilder.must(multiMatchQuery); 242 } 243 } 244 /** 245 * @param sortByPrice 246 * @param sortByCommission 247 * @param sortBySalesVolume 248 * @return 249 */ 250 @SuppressWarnings("rawtypes") 251 private SortBuilder getSortBuilder(EsProductQuery esProductQuery) { 252 switch (esProductQuery.getSortByPrice()) { 253 case -1: 254 return SortBuilders.fieldSort("price").order(SortOrder.DESC); 255 case 1: 256 return SortBuilders.fieldSort("price").order(SortOrder.ASC); 257 default: 258 break; 259 } 260 261 switch (esProductQuery.getSortByCommission()) { 262 case -1: 263 return SortBuilders.fieldSort("commission").order(SortOrder.DESC); 264 case 1: 265 return SortBuilders.fieldSort("commission").order(SortOrder.ASC); 266 default: 267 break; 268 } 269 270 switch (esProductQuery.getSortByCommission()) { 271 case -1: 272 return SortBuilders.fieldSort("salesVolume").order(SortOrder.DESC); 273 case 1: 274 return SortBuilders.fieldSort("salesVolume").order(SortOrder.ASC); 275 default: 276 break; 277 } 278 return null; 279 } 280 281 }
有什么问题我们可以好好讨论
时间: 2024-10-24 16:12:13