|
|
@@ -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) {
|
|
|
// 是否分词
|