Browse Source

增加物料型号、品牌、类目分词搜索

wangyc 7 năm trước cách đây
mục cha
commit
04a08bddea

+ 185 - 49
mall-search/src/main/java/com/uas/search/service/impl/SearchServiceImpl.java

@@ -305,6 +305,15 @@ public class SearchServiceImpl implements SearchService {
         } else {
             SPage<Long> brandPage = getBrandIds(keyword, page, size, true);
             brandIds = brandPage.getContent();
+
+			if (CollectionUtils.isEmpty(brandIds)) {
+				List<String> keywordFields = new ArrayList<>();
+				keywordFields.add(SearchConstants.BRAND_NAMECN_FIELD);
+				keywordFields.add(SearchConstants.BRAND_NAMEEN_FIELD);
+				keyword = recursivelyBrands(keyword, keywordFields, true);
+				brandPage = getBrandIds(keyword, page, size, true);
+				brandIds = brandPage.getContent();
+			}
             sPage = new SPage<>(brandPage.getTotalPage(), brandPage.getTotalElement(), brandPage.getPage(), brandPage.getSize(), brandPage.isFirst(), brandPage.isLast());
         }
 
@@ -351,17 +360,19 @@ public class SearchServiceImpl implements SearchService {
         if (SearchUtils.isKeywordInvalid(keyword)) {
             throw new IllegalArgumentException("搜索关键词无效:" + keyword);
         }
-        BooleanQuery booleanQuery = new BooleanQuery();
-        if (tokenized) {
-            booleanQuery.add(SearchUtils.getBooleanQuery(SearchConstants.BRAND_NAMECN_FIELD, keyword),
-                BooleanClause.Occur.SHOULD);
-            booleanQuery.add(SearchUtils.getBooleanQuery(SearchConstants.BRAND_NAMEEN_FIELD, keyword),
-                BooleanClause.Occur.SHOULD);
-        } else {
-            booleanQuery.add(new TermQuery(new Term(SearchConstants.BRAND_NAMECN_UNTOKENIZED_FIELD, keyword.toLowerCase())), Occur.SHOULD);
-            booleanQuery.add(new TermQuery(new Term(SearchConstants.BRAND_NAMEEN_UNTOKENIZED_FIELD, keyword.toLowerCase())), Occur.SHOULD);
-        }
+
+        List<String> keywordFields = new ArrayList<>();
+		if (tokenized) {
+			keywordFields.add(SearchConstants.BRAND_NAMECN_FIELD);
+			keywordFields.add(SearchConstants.BRAND_NAMEEN_FIELD);
+		} else {
+			keywordFields.add(SearchConstants.BRAND_NAMECN_UNTOKENIZED_FIELD);
+			keywordFields.add(SearchConstants.BRAND_NAMEEN_UNTOKENIZED_FIELD);
+		}
+
+        BooleanQuery booleanQuery = queryBrands(keyword, keywordFields, tokenized);
         logger.info(booleanQuery.toString());
+
         SPage<Document> documents = getDocuments(SearchConstants.BRAND_TABLE_NAME, booleanQuery, new Sort(sortBrand(keyword)), page,
             size);
 
@@ -375,6 +386,21 @@ public class SearchServiceImpl implements SearchService {
         return sPage;
     }
 
+	private BooleanQuery queryBrands(String keyword, List<String> keywordFields, Boolean tokenized) {
+		BooleanQuery booleanQuery = new BooleanQuery();
+		if (!SearchUtils.isKeywordInvalid(keyword) && !CollectionUtils.isEmpty(keywordFields)) {
+			for (String keywordField : keywordFields) {
+				if (tokenized) {
+					booleanQuery.add(SearchUtils.getBooleanQuery(keywordField, keyword.toLowerCase()),
+						BooleanClause.Occur.SHOULD);
+				} else {
+					booleanQuery.add(new TermQuery(new Term(keywordField, keyword.toLowerCase())), Occur.SHOULD);
+				}
+			}
+		}
+		return booleanQuery;
+	}
+
 	/**
 	 * 获取品牌Document
 	 * @param keyword 关键词
@@ -1077,11 +1103,105 @@ public class SearchServiceImpl implements SearchService {
 
 		productsFields.add(SearchConstants.PRODUCT_PRIVATE_CMPCODE_FIELD);
 		productsFields.add(SearchConstants.PRODUCT_PRIVATE_PCMPCODE_FIELD);
-		map.put("stock", getGoodsIds(keyword, goodsFields, true, pageParams));
-		map.put("futures", getProductIds(keyword, pageParams));
+
+		// 现货
+		Map<String, Object> stock = getGoodsIds(keyword, goodsFields, true, pageParams);
+		// 如搜索无结果则分词
+		if (CollectionUtils.isEmpty(stock) || stock.get("content") == null || JSONObject.parseArray(stock.get("content").toString()).isEmpty()) {
+			keyword = recursivelyGetGoodsIds(keyword, null, true);
+			stock = getGoodsIds(keyword, goodsFields, true, pageParams);
+		}
+		// 期货
+		SPage<Long> futures = getProductIds(keyword, productsFields, true, pageParams);
+		// 如搜索无结果则分词
+		if (futures == null || CollectionUtils.isEmpty(futures.getContent())) {
+			keyword = recursivelyProductIds(keyword, productsFields, true);
+			futures = getProductIds(keyword, productsFields, true, pageParams);
+		}
+		map.put("stock", stock);
+		map.put("futures", futures);
 		return map;
 	}
 
+	/**
+	 * 递归查询物料(如果没有结果,则降低精度,直至长度为 1)
+	 *
+	 * @param keyword       关键词
+	 * @param keywordFields 要查询的字段
+	 * @param tokenized     是否分词
+	 * @return 最后一次搜索的关键词
+	 */
+	private String recursivelyProductIds(String keyword, List<String> keywordFields, Boolean tokenized) throws IOException {
+		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher(SearchConstants.PRODUCTS_PRIVATE_TABLE_NAME);
+		try {
+			BooleanQuery booleanQuery = queryProducts(keyword, keywordFields, tokenized);
+			logger.info(booleanQuery.toString());
+			TotalHitCountCollector collector = new TotalHitCountCollector();
+			indexSearcher.search(booleanQuery, collector);
+			// 如果没有结果,则降低精度,直至 keyword 长度为 1
+			if (collector.getTotalHits() < 1 && !SearchUtils.isKeywordInvalid(keyword) && keyword.length() > 1) {
+				return recursivelyProductIds(keyword.substring(0, keyword.length() - 1), keywordFields, tokenized);
+			}
+			return keyword;
+		} finally {
+			releaseIndexSearcher(indexSearcher);
+		}
+	}
+
+	/**
+	 * 递归查询品牌(如果没有结果,则降低精度,直至长度为 1)
+	 *
+	 * @param keyword       关键词
+	 * @param keywordFields 要查询的字段
+	 * @param tokenized     是否分词
+	 * @return 最后一次搜索的关键词
+	 */
+	private String recursivelyBrands(String keyword, List<String> keywordFields, Boolean tokenized) throws IOException {
+		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher(SearchConstants.BRAND_TABLE_NAME);
+		try {
+			BooleanQuery booleanQuery = queryBrands(keyword, keywordFields, tokenized);
+			logger.info(booleanQuery.toString());
+			TotalHitCountCollector collector = new TotalHitCountCollector();
+			indexSearcher.search(booleanQuery, collector);
+			// 如果没有结果,则降低精度,直至 keyword 长度为 1
+			if (collector.getTotalHits() < 1 && !SearchUtils.isKeywordInvalid(keyword) && keyword.length() > 1) {
+				return recursivelyBrands(keyword.substring(0, keyword.length() - 1), keywordFields, tokenized);
+			}
+			return keyword;
+		} finally {
+			releaseIndexSearcher(indexSearcher);
+		}
+	}
+
+	/**
+	 * 通过递归类目查询物料(如果没有结果,则降低精度,直至长度为 1)
+	 *
+	 * @param keyword       关键词
+	 * @return 最后一次搜索的关键词
+	 */
+	private String recursivelyKindsForSellers(String indexName, String keyword, Query query, String duplicateType) throws IOException {
+		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher(indexName);
+		try {
+			DuplicateFilter duplicateFilter = null;
+			if (!StringUtils.isEmpty(duplicateType)) {
+				if (duplicateType.equals(SearchConstants.BRAND)) {
+					duplicateFilter = new DuplicateFilter(indexName.equals(SearchConstants.GOODS_TABLE_NAME) ? SearchConstants.GOODS_PR_PBRAND_EN_CN_STUUID_UNTOKENIZED_FIELD : SearchConstants.PRODUCT_PRIVATE_PBRAND_ENUU_FIELD);
+				} else if (duplicateType.equals(SearchConstants.KIND)) {
+					duplicateFilter = new DuplicateFilter(indexName.equals(SearchConstants.GOODS_TABLE_NAME) ? SearchConstants.GOODS_KIND_STUUID_UNTOKENIZED_FIELD : SearchConstants.PRODUCT_PRIVATE_KIND_ENUU_FIELD);
+				}
+			}
+			TotalHitCountCollector collector = new TotalHitCountCollector();
+			indexSearcher.search(query, duplicateFilter, collector);
+			// 如果没有结果,则降低精度,直至 keyword 长度为 1
+			if (collector.getTotalHits() < 1 && !SearchUtils.isKeywordInvalid(keyword) && keyword.length() > 1) {
+				return recursivelyKindsForSellers(indexName, keyword.substring(0, keyword.length() - 1), query, duplicateType);
+			}
+			return keyword;
+		} finally {
+			releaseIndexSearcher(indexSearcher);
+		}
+	}
+
 	/**
 	 * @param keyword
 	 * @param keywordFields
@@ -1168,7 +1288,7 @@ public class SearchServiceImpl implements SearchService {
 	 * @param keyword
 	 * @return
 	 */
-	private SPage<Long> getProductIds(String keyword, PageParams pageParams) throws IOException{
+	private SPage<Long> getProductIds(String keyword, List<String> keywordFields, Boolean tokenized, PageParams pageParams) throws IOException{
 		if (pageParams == null) {
 			pageParams = new PageParams();
 		}
@@ -1177,16 +1297,7 @@ public class SearchServiceImpl implements SearchService {
 		if (pageParams.getSize() <= 0)
 			pageParams.setSize(20);
 
-		BooleanQuery q1 = new BooleanQuery();
-		q1.add(new TermQuery(new Term(SearchConstants.PRODUCT_PRIVATE_B2CENABLED_FIELD, String.valueOf(1))), BooleanClause.Occur.MUST);
-		BooleanQuery booleanQuery = new BooleanQuery();
-		booleanQuery.add(q1, BooleanClause.Occur.MUST);
-		if (!StringUtils.isEmpty(keyword)) {
-			BooleanQuery q2 = new BooleanQuery();
-			q2.add(createQuery(SearchConstants.PRODUCT_PRIVATE_PCMPCODE_FIELD, keyword, true,1), BooleanClause.Occur.SHOULD);
-			q2.add(createQuery(SearchConstants.PRODUCT_PRIVATE_CMPCODE_FIELD, keyword, true,1), BooleanClause.Occur.SHOULD);
-			booleanQuery.add(q2, BooleanClause.Occur.MUST);
-		}
+		BooleanQuery booleanQuery = queryProducts(keyword, keywordFields, tokenized);
 		logger.info(booleanQuery.toString());
 		SPage<Document> documents =  getDocuments(SearchConstants.PRODUCTS_PRIVATE_TABLE_NAME, booleanQuery, new Sort(sortProduct(keyword)), pageParams.getPage(), pageParams.getSize());
 
@@ -1653,44 +1764,68 @@ public class SearchServiceImpl implements SearchService {
 			throw new IllegalArgumentException("搜索关键词无效:" + keyword);
 		}
 		Map<String, SPage<Object>> map = new HashMap<>();
-		BooleanQuery goodsQuery = new BooleanQuery();
-		BooleanQuery productsQuery = new BooleanQuery();
         // TODO 卖家排序
         Sort sort = null;
 		// 未指定搜索的字段,则采用默认搜索逻辑
 		if (CollectionUtils.isEmpty(keywordFields)) {
 			Map<String, Query> boostQuerys = setSellersBoost(keyword);
 		} else {
-			BooleanQuery goodsBooleanQuery = new BooleanQuery();
-			for (String keywordField : keywordFields.get("goods")) {
-				if (!tokenized) {
-                    goodsBooleanQuery.add(new TermQuery(new Term(keywordField, keyword.toLowerCase())), BooleanClause.Occur.SHOULD);
-				} else {
-                    goodsBooleanQuery.add(SearchUtils.getBooleanQuery(keywordField, keyword), BooleanClause.Occur.SHOULD);
-				}
-				goodsQuery.add(goodsBooleanQuery, Occur.MUST);
-			}
+			Map<String, BooleanQuery> queryMap = queryKindForSellers(keyword, keywordFields, tokenized);
+			BooleanQuery goodsQuery = queryMap.get("goodsQuery");
+			BooleanQuery productsQuery = queryMap.get("productsQuery");
+
 			// 现货卖家
-			map.put("stock", querySellers(SearchConstants.GOODS_TABLE_NAME, page, size, goodsQuery, sort, duplicate));
+			SPage<Object> stock = querySellers(SearchConstants.GOODS_TABLE_NAME, page, size, goodsQuery, sort, duplicate);
+			if (duplicate.equals(SearchConstants.KIND) && (stock == null || CollectionUtils.isEmpty(stock.getContent()))) {
+				keyword = recursivelyKindsForSellers(SearchConstants.GOODS_TABLE_NAME, keyword, goodsQuery, duplicate);
+				goodsQuery = queryKindForSellers(keyword, keywordFields, tokenized).get("goodsQuery");
+				stock = querySellers(SearchConstants.GOODS_TABLE_NAME, page, size, goodsQuery, sort, duplicate);
+			}
+			map.put("stock", stock);
 			logger.info(goodsQuery.toString());
 
-            BooleanQuery productsBooleanQuery = new BooleanQuery();
-			for (String keywordField : keywordFields.get("products")) {
-                if (!tokenized) {
-                    productsBooleanQuery.add(new TermQuery(new Term(keywordField, keyword.toLowerCase())), BooleanClause.Occur.SHOULD);
-                } else {
-                    productsBooleanQuery.add(SearchUtils.getBooleanQuery(keywordField, keyword.toLowerCase()), BooleanClause.Occur.SHOULD);
-                }
-				productsQuery.add(productsBooleanQuery, Occur.MUST);
-            }
 			// 期货卖家
-			map.put("futures", querySellers(SearchConstants.PRODUCTS_PRIVATE_TABLE_NAME, page, size, productsQuery, sort, duplicate));
+			SPage<Object> futures = querySellers(SearchConstants.PRODUCTS_PRIVATE_TABLE_NAME, page, size, productsQuery, sort, duplicate);
+			if (duplicate.equals(SearchConstants.KIND) && (futures == null || CollectionUtils.isEmpty(futures.getContent()))) {
+				keyword = recursivelyKindsForSellers(SearchConstants.PRODUCTS_PRIVATE_TABLE_NAME, keyword, productsQuery, duplicate);
+				productsQuery = queryKindForSellers(keyword, keywordFields, tokenized).get("productsQuery");
+				futures = querySellers(SearchConstants.PRODUCTS_PRIVATE_TABLE_NAME, page, size, productsQuery, sort, duplicate);
+			}
+			map.put("futures", futures);
 			logger.info(productsQuery.toString());
 		}
-
 		return map;
 	}
 
+	private Map<String, BooleanQuery> queryKindForSellers(String keyword, Map<String, List<String>> keywordFields, boolean tokenized) {
+		Map<String, BooleanQuery> booleanQueryMap = new HashMap<>();
+		BooleanQuery goodsQuery = new BooleanQuery();
+		BooleanQuery productsQuery = new BooleanQuery();
+		BooleanQuery goodsBooleanQuery = new BooleanQuery();
+		BooleanQuery productsBooleanQuery = new BooleanQuery();
+
+		for (String keywordField : keywordFields.get("goods")) {
+			if (!tokenized) {
+				goodsBooleanQuery.add(new TermQuery(new Term(keywordField, keyword.toLowerCase())), BooleanClause.Occur.SHOULD);
+			} else {
+				goodsBooleanQuery.add(SearchUtils.getBooleanQuery(keywordField, keyword), BooleanClause.Occur.SHOULD);
+			}
+			goodsQuery.add(goodsBooleanQuery, Occur.MUST);
+		}
+		for (String keywordField : keywordFields.get("products")) {
+			if (!tokenized) {
+				productsBooleanQuery.add(new TermQuery(new Term(keywordField, keyword.toLowerCase())), BooleanClause.Occur.SHOULD);
+			} else {
+				productsBooleanQuery.add(SearchUtils.getBooleanQuery(keywordField, keyword.toLowerCase()), BooleanClause.Occur.SHOULD);
+			}
+			productsQuery.add(productsBooleanQuery, Occur.MUST);
+		}
+
+		booleanQueryMap.put("goodsQuery", goodsQuery);
+		booleanQueryMap.put("productsQuery", productsQuery);
+
+		return booleanQueryMap;
+	}
 	private SPage<Object> querySellers(String indexName, Integer page, Integer size, Query query, Sort sort, String duplicateType)  throws IOException {
 		SPage<Object> sPage = new SPage<>();
 		if (page != null && page > 0) {
@@ -1888,11 +2023,12 @@ public class SearchServiceImpl implements SearchService {
 
 	private BooleanQuery queryProducts(String keyword, List<String> keywordFields, Boolean tokenized) {
 		BooleanQuery booleanQuery = new BooleanQuery();
+		BooleanQuery q1 = new BooleanQuery();
+		q1.add(new TermQuery(new Term(SearchConstants.PRODUCT_PRIVATE_B2CENABLED_FIELD, String.valueOf(1))), BooleanClause.Occur.MUST);
+		booleanQuery.add(q1, BooleanClause.Occur.MUST);
 		if (!SearchUtils.isKeywordInvalid(keyword)) {
 			// 未指定搜索的字段,则采用默认搜索逻辑
-			if (CollectionUtils.isEmpty(keywordFields)) {
-//				booleanQuery.add(setGoodsBoost(keyword), BooleanClause.Occur.MUST);
-			} else {
+			if (!CollectionUtils.isEmpty(keywordFields)) {
 				BooleanQuery booleanQuery2 = new BooleanQuery();
 				for (String keywordField : keywordFields) {
 					// 是否分词