Przeglądaj źródła

增加搜索卖家接口

wangyc 7 lat temu
rodzic
commit
5fcb808d7f

+ 26 - 0
mall-search/src/main/java/com/uas/search/constant/SearchConstants.java

@@ -38,11 +38,21 @@ public class SearchConstants {
 	 */
 	public static final String KIND_TABLE_NAME = "product$kind";
 
+	/**
+	 * 类目
+	 */
+	public static final String KIND = "kind";
+
 	/**
 	 * 品牌表名
 	 */
 	public static final String BRAND_TABLE_NAME = "product$brand";
 
+	/**
+	 * 品牌
+	 */
+	public static final String BRAND = "brand";
+
 	/**
 	 * 器件表名
 	 */
@@ -185,6 +195,14 @@ public class SearchConstants {
     public static final String GOODS_BR_WEIGHT_FIELD = "br_weight";
 	public static final String GOODS_PR_ID_FIELD = "pr_id";
 	public static final String GOODS_PR_PCMPCODE_FIELD = "pr_pcmpcode";
+	public static final String GOODS_PR_PBRAND_EN_FIELD = "pr_pbranden";
+	public static final String GOODS_PR_PBRAND_CN_FIELD = "pr_pbrand";
+	public static final String GOODS_PR_PBRAND_EN_UNTOKENIZED_FIELD = "pr_pbranden_untokenized";
+	public static final String GOODS_PR_PBRAND_CN_UNTOKENIZED_FIELD = "pr_pbrand_untokenized";
+	public static final String GOODS_PR_PBRAND_EN_CN_STUUID_UNTOKENIZED_FIELD = "pr_pbranden_cn_stuuid_untokenized";
+	public static final String GOODS_PR_KIND_FIELD = "pr_kind";
+	public static final String GOODS_PR_KIND_UNTOKENIZED_FIELD = "pr_kind_untokenized";
+	public static final String GOODS_KIND_STUUID_UNTOKENIZED_FIELD = "pr_kind_stuuid_untokenized";
 	// 自动生成的字段,用于唯一区分批次索引
     public static final String GOODS_PRIMARY_KEY_FIELD = "primary_key";
 
@@ -301,8 +319,16 @@ public class SearchConstants {
     /**
      * 标准字段
      */
+	// 品牌英文名
+	public static final String PRODUCT_PRIVATE_PBRAND_EN_FIELD = "pr_pbranden";
+	// 品牌中文名
+	public static final String PRODUCT_PRIVATE_PBRAND_CN_FIELD = "pr_pbrand";
+	// 品牌+enuu
+	public static final String PRODUCT_PRIVATE_PBRAND_ENUU_FIELD = "pr_pbrand_enuu";
     // 类目
     public static final String PRODUCT_PRIVATE_KIND_FIELD = "pr_kind";
+	// 类目+enuu
+	public static final String PRODUCT_PRIVATE_KIND_ENUU_FIELD = "pr_kind_enuu";
     // 标准型号
     public static final String PRODUCT_PRIVATE_PCMPCODE_FIELD = "pr_pcmpcode";
     // 标准英文品牌

+ 5 - 0
mall-search/src/main/java/com/uas/search/constant/model/PageParams.java

@@ -200,6 +200,11 @@ public class PageParams implements Serializable {
 		 */
 		GOODS_MAXPRICEUSD,
 
+		/**
+		 * 物料可用状态
+		 */
+		PRODUCT_STATUS,
+
 		// 以下字段用于单据搜索
 
 		/**

+ 31 - 0
mall-search/src/main/java/com/uas/search/controller/SearchController.java

@@ -134,6 +134,37 @@ public class SearchController {
 		return searchService.getBrands(keyword, page, size);
 	}
 
+	/**
+	 * 根据关键词搜索品牌(精确命中后,提供卖家信息)
+	 * @param keyword 关键词
+	 * @param page 页码
+	 * @param size 页数
+	 * @param request 请求
+	 * @return
+	 * @throws IOException
+	 */
+	@RequestMapping("/brandsAndSellers")
+	@ResponseBody
+	public SPage<Map<String, Object>> searchBrandAndSellers(@RequestParam String keyword, Integer page, Integer size, HttpServletRequest request) throws IOException {
+		return searchService.getBrandsAndSellers(keyword, page, size);
+	}
+
+	/**
+	 * 根据类目关键词搜索卖家信息
+	 * @param keyword 关键词
+	 * @param page 页码
+	 * @param size 页数
+	 * @param request 请求
+	 * @return
+	 * @throws IOException
+	 */
+	@RequestMapping("/kindsAndSellers")
+	@ResponseBody
+	public Map<String, Object> searchSellersWithKind(@RequestParam String keyword, Integer page, Integer size, HttpServletRequest request) throws IOException {
+		return searchService.getSellersWithKind(keyword, page, size);
+	}
+
+
     @RequestMapping("/componentIds")
     @ResponseBody
     public Map<String, Object> searchComponentIds(@RequestParam String keyword, String params, HttpServletRequest request) {

+ 14 - 0
mall-search/src/main/java/com/uas/search/model/Products.java

@@ -46,6 +46,12 @@ public class Products implements RowMapper, Serializable {
     @Column(name = "pr_pbrand")
     private String pBrandCn;
 
+    /**
+     * 类目名称
+     */
+    @Column(name = "pr_kind")
+    private String kind;
+
     /**
      * 是否标准(1标准 ,非1 非标)
      */
@@ -84,6 +90,14 @@ public class Products implements RowMapper, Serializable {
         this.pBrandCn = pBrandCn;
     }
 
+    public String getKind() {
+        return kind;
+    }
+
+    public void setKind(String kind) {
+        this.kind = kind;
+    }
+
     public Short getStandard() {
         return standard;
     }

+ 1 - 1
mall-search/src/main/java/com/uas/search/model/V_Products.java

@@ -18,7 +18,7 @@ import org.springframework.jdbc.core.RowMapper;
 @Entity
 @Table(name = "v$product$private")
 public class V_Products implements RowMapper, Serializable {
-
+    public static final Short[] VALID_STATUS = {0};
     /**
      * 序列号
      */

+ 20 - 0
mall-search/src/main/java/com/uas/search/service/SearchService.java

@@ -72,6 +72,26 @@ public interface SearchService {
 	 */
 	public SPage<Map<String, Object>> getBrands(String keyword, Integer page, Integer size) throws IOException;
 
+	/**
+	 * 根据关键词搜索品牌(精确命中后,提供卖家信息)
+	 * @param keyword 关键词
+	 * @param page 页码
+	 * @param size 页数
+	 * @return
+	 * @throws IOException
+	 */
+	SPage<Map<String, Object>> getBrandsAndSellers(String keyword, Integer page, Integer size) throws IOException;
+
+	/**
+	 * 根据关键词搜索品牌(精确命中后,提供卖家信息)
+	 * @param keyword 关键词
+	 * @param page 页码
+	 * @param size 页数
+	 * @return
+	 * @throws IOException
+	 */
+	Map<String, Object> getSellersWithKind(String keyword, Integer page, Integer size) throws IOException;
+
 	/**
 	 * 根据关键词搜索产品(关键词可能是器件、类目、品牌,甚至可能是类目、品牌的混合)
 	 * 

+ 402 - 51
mall-search/src/main/java/com/uas/search/service/impl/SearchServiceImpl.java

@@ -1,5 +1,10 @@
 package com.uas.search.service.impl;
 
+import static com.uas.search.constant.model.Sort.Field.PRICE;
+import static com.uas.search.constant.model.Sort.Field.RESERVE;
+import static com.uas.search.util.SearchUtils.getDocuments;
+import static com.uas.search.util.SearchUtils.releaseIndexSearcher;
+
 import com.alibaba.fastjson.JSONObject;
 import com.uas.search.annotation.NotEmpty;
 import com.uas.search.constant.SearchConstants;
@@ -23,8 +28,18 @@ import com.uas.search.util.DocumentToObjectUtils;
 import com.uas.search.util.ObjectToDocumentUtils;
 import com.uas.search.util.SearchUtils;
 import com.uas.search.util.StringUtils;
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.sandbox.queries.DuplicateFilter;
 import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.BooleanQuery;
@@ -43,19 +58,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
-import java.io.IOException;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static com.uas.search.constant.model.Sort.Field.PRICE;
-import static com.uas.search.constant.model.Sort.Field.RESERVE;
-
 /**
  * 搜索索引
  * 
@@ -90,6 +92,16 @@ public class SearchServiceImpl implements SearchService {
 	 */
 	private static final String NONSTANDARD_PRODUCTS = "nStandard";
 
+	/**
+	 * 默认的页码
+	 */
+	private static final int PAGE_INDEX = 1;
+
+	/**
+	 * 默认每页的大小
+	 */
+	private static final int PAGE_SIZE = 20;
+
 	private static Logger logger = LoggerFactory.getLogger(SearchServiceImpl.class);
 
 	/**
@@ -140,7 +152,7 @@ public class SearchServiceImpl implements SearchService {
 			booleanQuery.add(q2, BooleanClause.Occur.MUST);
 		}
 		logger.info(booleanQuery.toString());
-		return SearchUtils.getDocuments(SearchConstants.PRODUCTS_PRIVATE_TABLE_NAME, booleanQuery, new Sort(sortProduct(keyword)), page, size);
+		return getDocuments(SearchConstants.PRODUCTS_PRIVATE_TABLE_NAME, booleanQuery, new Sort(sortProduct(keyword)), page, size);
 	}
 
 	/**
@@ -187,7 +199,7 @@ public class SearchServiceImpl implements SearchService {
 		}
 		BooleanQuery booleanQuery = SearchUtils.getBooleanQuery(SearchConstants.KIND_NAMECN_FIELD, keyword);
 		logger.info(booleanQuery.toString());
-		return SearchUtils.getDocuments(SearchConstants.KIND_TABLE_NAME, booleanQuery, new Sort(sortKind(keyword)), page, size);
+		return getDocuments(SearchConstants.KIND_TABLE_NAME, booleanQuery, new Sort(sortKind(keyword)), page, size);
 	}
 
     /**
@@ -250,17 +262,120 @@ public class SearchServiceImpl implements SearchService {
 		return sPage;
 	}
 
+	@Override
+	public SPage<Map<String, Object>> getBrandsAndSellers(String keyword, Integer page, Integer size)
+		throws IOException {
+		List<Map<String, Object>> content = new ArrayList<>();
+        Map<String, Object> map = new HashMap<>();
+        List<Long> brandIds = new ArrayList<>();
+        SPage<Object> stock = null;
+		SPage<Object> futures = null;
+
+        // 精准匹配
+        SPage<Long> documents = getBrandIds(keyword, page, size, false);
+        SPage<Map<String, Object>> sPage = new SPage<>(1, 1, 1, documents.getSize(), true, true);
+        // 精准匹配成功
+        if (!CollectionUtils.isEmpty(documents.getContent())) {
+            List<String> keywordFeilds = new ArrayList<>();
+            keywordFeilds.add(SearchConstants.GOODS_PR_PBRAND_EN_UNTOKENIZED_FIELD);
+            keywordFeilds.add(SearchConstants.GOODS_PR_PBRAND_CN_UNTOKENIZED_FIELD);
+
+            brandIds.add(documents.getContent().get(0));
+            // 获取卖家信息
+            Map<String, SPage<Object>> sellers = querySellers(keyword, keywordFeilds, page, size, false, SearchConstants.BRAND);
+			stock = sellers.get("stock");
+			futures = sellers.get("futures");
+
+            map.put("stock", stock);
+            map.put("futures", futures);
+        // 模糊匹配
+        } else {
+            SPage<Long> brandPage = getBrandIds(keyword, page, size, true);
+            brandIds = brandPage.getContent();
+            sPage = new SPage<>(brandPage.getTotalPage(), brandPage.getTotalElement(), brandPage.getPage(), brandPage.getSize(), brandPage.isFirst(), brandPage.isLast());
+        }
+
+		map.put("brandIds", brandIds);
+		content.add(map);
+        sPage.setContent(content);
+        return sPage;
+	}
+
+	@Override
+	public Map<String, Object> getSellersWithKind(String keyword, Integer page, Integer size)
+		throws IOException {
+		Map<String, Object> map = new HashMap<>();
+		SPage<Object> stock = null;
+		SPage<Object> futures = null;
+		List<String> keywordFeilds = new ArrayList<>();
+		keywordFeilds.add(SearchConstants.GOODS_PR_KIND_FIELD);
+		Map<String, SPage<Object>> sellers = querySellers(keyword, keywordFeilds, page, size, true, SearchConstants.KIND);
+		stock = sellers.get("stock");
+		futures = sellers.get("futures");
+
+		map.put("stock", stock);
+		map.put("futures", futures);
+		return map;
+	}
+
+	/**
+     * 获取品牌id
+     * @param keyword
+     * @param page
+     * @param size
+     * @return
+     */
+    private SPage<Long> getBrandIds(String keyword, Integer page, Integer size, Boolean tokenized) throws IOException{
+        List<Long> brandIds = new ArrayList<>();
+        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);
+        }
+        logger.info(booleanQuery.toString());
+        SPage<Document> documents = getDocuments(SearchConstants.BRAND_TABLE_NAME, booleanQuery, new Sort(sortBrand(keyword)), page,
+            size);
+
+        SPage<Long> sPage = new SPage<Long>(documents.getTotalPage(),
+            documents.getTotalElement(), documents.getPage(), documents.getSize(), documents.isFirst(),
+            documents.isLast());
+        for (Document document : documents.getContent()) {
+            brandIds.add(Long.parseLong(document.get(SearchConstants.BRAND_ID_FIELD)));
+        }
+        sPage.setContent(brandIds);
+        return sPage;
+    }
+
+	/**
+	 * 获取品牌Document
+	 * @param keyword 关键词
+	 * @param page 页码
+	 * @param size 页数
+	 * @return
+	 * @throws IOException
+	 */
 	private SPage<Document> getBrandDocuments(String keyword, Integer page, Integer size) throws IOException {
 		if (SearchUtils.isKeywordInvalid(keyword)) {
 			throw new IllegalArgumentException("搜索关键词无效:" + keyword);
 		}
+
 		BooleanQuery booleanQuery = new BooleanQuery();
+
 		booleanQuery.add(SearchUtils.getBooleanQuery(SearchConstants.BRAND_NAMECN_FIELD, keyword),
-				BooleanClause.Occur.SHOULD);
+			BooleanClause.Occur.SHOULD);
 		booleanQuery.add(SearchUtils.getBooleanQuery(SearchConstants.BRAND_NAMEEN_FIELD, keyword),
-				BooleanClause.Occur.SHOULD);
+			BooleanClause.Occur.SHOULD);
+
 		logger.info(booleanQuery.toString());
-		return SearchUtils.getDocuments(SearchConstants.BRAND_TABLE_NAME, booleanQuery, new Sort(sortBrand(keyword)), page,
+		return getDocuments(SearchConstants.BRAND_TABLE_NAME, booleanQuery, new Sort(sortBrand(keyword)), page,
 				size);
 	}
 
@@ -434,7 +549,7 @@ public class SearchServiceImpl implements SearchService {
 		} catch (IOException e) {
 			logger.error("", e);
 		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+			releaseIndexSearcher(indexSearcher);
 		}
 		return map;
 	}
@@ -555,7 +670,7 @@ public class SearchServiceImpl implements SearchService {
 		} catch (IOException e) {
 			throw new IllegalStateException("统计失败", e);
 		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+			releaseIndexSearcher(indexSearcher);
 		}
 	}
 
@@ -630,7 +745,7 @@ public class SearchServiceImpl implements SearchService {
 		} catch (IOException e) {
 			logger.error("", e);
 		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+			releaseIndexSearcher(indexSearcher);
 		}
 		return components;
 	}
@@ -654,7 +769,7 @@ public class SearchServiceImpl implements SearchService {
 
         Sort sort = new Sort(new SortField(SearchConstants.BRAND_NAMEEN_UNTOKENIZED_FIELD, new StringFieldComparatorSource(brandName)),
                 new SortField(SearchConstants.BRAND_NAMECN_UNTOKENIZED_FIELD, new StringFieldComparatorSource(brandName)));
-		List<Document> documents = SearchUtils.getDocuments(SearchConstants.BRAND_TABLE_NAME, booleanQuery, sort, null, size)
+		List<Document> documents = getDocuments(SearchConstants.BRAND_TABLE_NAME, booleanQuery, sort, null, size)
 				.getContent();
 		for (Document document : documents) {
 			Map<String, Object> brand = new HashMap<>();
@@ -719,7 +834,7 @@ public class SearchServiceImpl implements SearchService {
 		logger.info(booleanQuery.toString());
 
         Sort sort = new Sort(new SortField(SearchConstants.KIND_NAMECN_UNTOKENIZED_FIELD, new StringFieldComparatorSource(kindName)));
-		List<Document> documents = SearchUtils.getDocuments(SearchConstants.KIND_TABLE_NAME, booleanQuery, sort, null, size).getContent();
+		List<Document> documents = getDocuments(SearchConstants.KIND_TABLE_NAME, booleanQuery, sort, null, size).getContent();
 		for (Document document : documents) {
 			Map<String, Object> map = new HashMap<>();
 			map.put("id", Long.parseLong(document.get(SearchConstants.KIND_ID_FIELD)));
@@ -777,7 +892,7 @@ public class SearchServiceImpl implements SearchService {
 		} catch (IOException e) {
 			logger.error("", e);
 		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+			releaseIndexSearcher(indexSearcher);
 		}
 
 		List<Map<String, String>> result = new ArrayList<>();
@@ -878,7 +993,7 @@ public class SearchServiceImpl implements SearchService {
 		} catch (IOException e) {
 			logger.error("", e);
 		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+			releaseIndexSearcher(indexSearcher);
 		}
 		return result;
 	}
@@ -921,17 +1036,29 @@ public class SearchServiceImpl implements SearchService {
 
 	@Override
 	public Map<String, Object> getGoodsIds(String keyword, PageParams pageParams) throws IOException {
-		List<String> keywordFields = new ArrayList<>();
+//		List<String> keywordFields = new ArrayList<>();
 		// 先根据品牌搜索,品牌不存在再搜索型号等
-		keywordFields.add(SearchConstants.GOODS_BR_NAME_CN_UNTOKENIZED_FIELD);
-		keywordFields.add(SearchConstants.GOODS_BR_NAME_EN_UNTOKENIZED_FIELD);
-		Map<String, Object> goodsIds = getGoodsIds(keyword, keywordFields, false, pageParams);
-		if (CollectionUtils.isEmpty(goodsIds) || goodsIds.get("componentIds") == null
-				|| JSONObject.parseArray(goodsIds.get("componentIds").toString()).isEmpty()) {
-            keyword = recursivelyGetGoodsIds(keyword, null, true);
-			goodsIds = getGoodsIds(keyword, null, true, pageParams);
-		}
-		return goodsIds;
+//		keywordFields.add(SearchConstants.GOODS_BR_NAME_CN_UNTOKENIZED_FIELD);
+//		keywordFields.add(SearchConstants.GOODS_BR_NAME_EN_UNTOKENIZED_FIELD);
+//		Map<String, Object> goodsIds = getGoodsIds(keyword, keywordFields, false, pageParams);
+//		if (CollectionUtils.isEmpty(goodsIds) || goodsIds.get("componentIds") == null
+//				|| JSONObject.parseArray(goodsIds.get("componentIds").toString()).isEmpty()) {
+//            keyword = recursivelyGetGoodsIds(keyword, null, true);
+//			goodsIds = getGoodsIds(keyword, null, true, pageParams);
+//		}
+//		return goodsIds;
+		Map<String, Object> map = new HashMap<>();
+		List<String> goodsFields = new ArrayList<>();
+		List<String> productsFields = new ArrayList<>();
+		// 先根据品牌搜索,品牌不存在再搜索型号等
+		goodsFields.add(SearchConstants.GOODS_PR_PCMPCODE_FIELD);
+		goodsFields.add(SearchConstants.GOODS_CMP_CODE_FIELD);
+
+		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));
+		return map;
 	}
 
 	/**
@@ -958,7 +1085,7 @@ public class SearchServiceImpl implements SearchService {
 			pageParams.setSize(20);
 
 		Map<String, Object> map = new HashMap<String, Object>();
-		List<Long> cmpIds = new ArrayList<>();
+//		List<Long> cmpIds = new ArrayList<>();
 		List<Long> goIds = new ArrayList<>();
 		try {
 			BooleanQuery booleanQuery = queryGoods(keyword, keywordFields, tokenized);
@@ -983,29 +1110,69 @@ public class SearchServiceImpl implements SearchService {
 
 			// 数据量太大,需要指定将获取的数据(以免载入不必要的数据,降低速度)
 			Set<String> fieldsToLoad = new HashSet<>();
-			fieldsToLoad.add(SearchConstants.GOODS_CMP_ID_FIELD);
+//			fieldsToLoad.add(SearchConstants.GOODS_CMP_ID_FIELD);
 			fieldsToLoad.add(SearchConstants.GOODS_GO_ID_FIELD);
 			ScoreDoc[] scoreDocs = hits.scoreDocs;
 			for (ScoreDoc scoreDoc : scoreDocs) {
 				Document document = indexSearcher.doc(scoreDoc.doc, fieldsToLoad);
-                String cmpId = document.get(SearchConstants.GOODS_CMP_ID_FIELD);
-				cmpIds.add(StringUtils.isEmpty(cmpId) || cmpId.equals(ObjectToDocumentUtils.NULL_VALUE) ? null : Long.valueOf(cmpId));
+//                String cmpId = document.get(SearchConstants.GOODS_CMP_ID_FIELD);
+//				cmpIds.add(StringUtils.isEmpty(cmpId) || cmpId.equals(ObjectToDocumentUtils.NULL_VALUE) ? null : Long.valueOf(cmpId));
 				String goId = document.get(SearchConstants.GOODS_GO_ID_FIELD);
 				goIds.add(StringUtils.isEmpty(goId) || goId.equals(ObjectToDocumentUtils.NULL_VALUE) ? null : Long.valueOf(goId));
 			}
-			map.put("componentIds", cmpIds);
-			map.put("goodsIds", goIds);
+//			map.put("componentIds", cmpIds);
+			map.put("content", goIds);
 			map.put("page", pageParams.getPage());
 			map.put("size", pageParams.getSize());
-			map.put("total", hits.totalHits);
+			map.put("totalElement", hits.totalHits);
+			int totalPage = (int) Math.ceil(hits.totalHits / (1.0 * pageParams.getSize()));
+			map.put("totalPage", totalPage);
+			map.put("last", totalPage == pageParams.getPage() ? true : false);
+			map.put("first", pageParams.getPage() == 1 ? true : false);
 		} catch (IOException e) {
 			logger.error("", e);
 		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+			releaseIndexSearcher(indexSearcher);
 		}
 		return map;
 	}
 
+	/**
+	 * 获取物料信息
+	 * @param keyword
+	 * @return
+	 */
+	private SPage<Long> getProductIds(String keyword, PageParams pageParams) throws IOException{
+		if (pageParams == null) {
+			pageParams = new PageParams();
+		}
+		if (pageParams.getPage() <= 0)
+			pageParams.setPage(1);
+		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);
+		}
+		logger.info(booleanQuery.toString());
+		SPage<Document> documents =  getDocuments(SearchConstants.PRODUCTS_PRIVATE_TABLE_NAME, booleanQuery, new Sort(sortProduct(keyword)), pageParams.getPage(), pageParams.getSize());
+
+		SPage<Long> sPage = new SPage<>(documents.getTotalPage(), documents.getTotalElement(), documents.getPage(), documents.getSize(), documents.isFirst(), documents.isLast());
+		List<Long> productIds = new ArrayList<>();
+		for (Document document : documents.getContent()) {
+			productIds.add(Long.parseLong(document.get(SearchConstants.PRODUCT_PRIVATE_ID_FIELD)));
+		}
+		sPage.setContent(productIds);
+		return sPage;
+	}
+
     /**
      * 递归查询批次(如果没有结果,则降低精度,直至长度为 1)
      *
@@ -1027,7 +1194,7 @@ public class SearchServiceImpl implements SearchService {
             }
             return keyword;
         } finally {
-            SearchUtils.releaseIndexSearcher(indexSearcher);
+            releaseIndexSearcher(indexSearcher);
         }
     }
 
@@ -1119,6 +1286,31 @@ public class SearchServiceImpl implements SearchService {
         }
     }
 
+	/**
+	 * 设置批次过滤条件
+	 *
+	 * @param filters 指定的过滤条件
+	 * @param query   原查询
+	 */
+	private void setProductsFilter(Map<FilterField, Object> filters, BooleanQuery query) {
+		Object status;
+		// 筛选状态
+		if (!CollectionUtils.isEmpty(filters) && !StringUtils.isEmpty(filters.get(FilterField.PRODUCT_STATUS))) {
+			// 如果明确指定了状态,则直接过滤物料
+			status = filters.get(FilterField.PRODUCT_STATUS);
+			filter(status, SearchConstants.PRODUCT_PRIVATE_B2CENABLED_FIELD, query);
+		} else {
+			// 如果未明确指定状态,则使用默认状态分情况进行过滤(结果中包括没有批次的器件)
+			status = Arrays.asList(V_Products.VALID_STATUS);
+			// 或者批次 id 为空(此时是器件)
+			BooleanQuery q2 = new BooleanQuery();
+
+			BooleanQuery booleanQuery = new BooleanQuery();
+			booleanQuery.add(q2, Occur.SHOULD);
+			query.add(booleanQuery, Occur.FILTER);
+		}
+	}
+
     /**
      * 批次排序规则
      */
@@ -1238,7 +1430,7 @@ public class SearchServiceImpl implements SearchService {
         } catch (IOException e) {
             logger.error("", e);
         } finally {
-            SearchUtils.releaseIndexSearcher(indexSearcher);
+            releaseIndexSearcher(indexSearcher);
         }
         return map;
     }
@@ -1263,7 +1455,7 @@ public class SearchServiceImpl implements SearchService {
             }
             return keyword;
         } finally {
-            SearchUtils.releaseIndexSearcher(indexSearcher);
+            releaseIndexSearcher(indexSearcher);
         }
     }
 
@@ -1418,6 +1610,143 @@ public class SearchServiceImpl implements SearchService {
 		return result;
 	}
 
+	/**
+	 * 获取卖家信息
+	 * @param keyword 关键词
+	 * @param keywordFields 搜索字段
+	 * @param page 页码
+	 * @param size 页数
+	 * @param tokenized 是否分词
+	 * @param duplicate 去重类型
+	 * @return
+	 */
+	private Map<String, SPage<Object>> querySellers(String keyword, List<String> keywordFields, Integer page, Integer size, boolean tokenized, String duplicate) throws IOException {
+		if (SearchUtils.isKeywordInvalid(keyword)) {
+			throw new IllegalArgumentException("搜索关键词无效:" + keyword);
+		}
+		// 现货卖家
+		Map<String, SPage<Object>> map = new HashMap<>();
+		// 期货卖家
+		BooleanQuery booleanQuery = new BooleanQuery();
+
+		// 未指定搜索的字段,则采用默认搜索逻辑
+		if (CollectionUtils.isEmpty(keywordFields)) {
+			Map<String, Query> boostQuerys = setSellersBoost(keyword);
+		} else {
+			BooleanQuery booleanQuery2 = new BooleanQuery();
+			for (String keywordField : keywordFields) {
+				if (!tokenized) {
+					booleanQuery2.add(new TermQuery(new Term(keywordField, keyword.toLowerCase())), BooleanClause.Occur.SHOULD);
+				} else {
+					booleanQuery2.add(SearchUtils.getBooleanQuery(keywordField, keyword), BooleanClause.Occur.SHOULD);
+				}
+				booleanQuery.add(booleanQuery2, Occur.MUST);
+			}
+			logger.info(booleanQuery.toString());
+		}
+		// TODO 卖家排序
+		Sort sort = null;
+		// 现货卖家
+		map.put("stock", querySellers(SearchConstants.GOODS_TABLE_NAME, page, size, booleanQuery, sort, duplicate));
+		// 期货卖家
+		map.put("futures", querySellers(SearchConstants.PRODUCTS_PRIVATE_TABLE_NAME, page, size, booleanQuery, sort, duplicate));
+		return map;
+	}
+
+	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) {
+			sPage.setPage(page);
+		} else {
+			sPage.setPage(PAGE_INDEX);
+			sPage.setFirst(true);
+		}
+		if (size != null && size > 0) {
+			sPage.setSize(size);
+		} else {
+			sPage.setSize(PAGE_SIZE);
+		}
+
+		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);
+			}
+		}
+
+		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher(indexName);
+		TopDocs topDocs;
+		try {
+			// 如果页码不为1
+			if (sPage.getPage() > 1) {
+				TopDocs previousTopDocs;
+				if (sort == null) {
+					previousTopDocs = duplicateFilter == null ? indexSearcher.search(query, (sPage.getPage() - 1) * sPage.getSize()) : indexSearcher.search(query, duplicateFilter, (sPage.getPage() - 1) * sPage.getSize());
+				} else {
+					previousTopDocs = indexSearcher.search(query, duplicateFilter, (sPage.getPage() - 1) * sPage.getSize(), sort);
+				}
+				int totalHits = previousTopDocs.totalHits;
+				ScoreDoc[] previousScoreDocs = previousTopDocs.scoreDocs;
+				if ((sPage.getPage() - 1) * sPage.getSize() >= totalHits) {
+					throw new IllegalArgumentException("页码过大:元素总数量为" + totalHits);
+				}
+				topDocs = sort == null ? indexSearcher.searchAfter(previousScoreDocs[previousScoreDocs.length - 1], query, sPage.getSize()) :
+					indexSearcher.searchAfter(previousScoreDocs[previousScoreDocs.length - 1], query, sPage.getSize(), sort);
+			} else {
+				sPage.setFirst(true);
+				if (sort == null) {
+					topDocs = duplicateFilter == null ? indexSearcher.search(query, sPage.getSize()) : indexSearcher.search(query, duplicateFilter, sPage.getSize());
+				} else {
+					topDocs = duplicateFilter == null ? indexSearcher.search(query, sPage.getSize(), sort) : indexSearcher.search(query, duplicateFilter, sPage.getSize(), sort);
+				}
+			}
+
+			int totalHits = topDocs.totalHits;
+			// 设置总元素个数、页数等信息
+			sPage.setTotalElement(totalHits);
+			int totalPage = (int) Math.ceil(totalHits / (1.0 * sPage.getSize()));
+			sPage.setTotalPage(totalPage);
+			if (totalPage == sPage.getPage()) {
+				sPage.setLast(true);
+			}
+
+			List<Document> documents = new ArrayList<>();
+			for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
+				documents.add(indexSearcher.doc(scoreDoc.doc));
+			}
+
+			List<Object> content = new ArrayList<>();
+			if (indexName.equals(SearchConstants.GOODS_TABLE_NAME)) {
+				for (Document document : documents) {
+					content.add(document.get(SearchConstants.GOODS_ST_UUID_FIELD));
+				}
+			} else if (indexName.equals(SearchConstants.PRODUCTS_PRIVATE_TABLE_NAME)) {
+				for (Document document : documents) {
+					content.add(Long.parseLong(document.get(SearchConstants.PRODUCT_PRIVATE_ENUU_FIELD)));
+				}
+			}
+			sPage.setContent(content);
+		} finally {
+			releaseIndexSearcher(indexSearcher);
+		}
+		return sPage;
+	}
+
+	private Map<String, Query> setSellersBoost(String keyword) {
+		// TODO
+		Map<String, Query> queryMap = new HashMap<>();
+		BooleanQuery goodsQuery = new BooleanQuery();
+		BooleanQuery productsQuery = new BooleanQuery();
+		return null;
+	}
+
+	private SortField[] sortSellers(String keyword) {
+		// TODO
+		return null;
+	}
+
 	/**
 	 * @param keyword
 	 * @param keywordFields
@@ -1474,7 +1803,7 @@ public class SearchServiceImpl implements SearchService {
 		} catch (IOException e) {
 			logger.error("", e);
 		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+			releaseIndexSearcher(indexSearcher);
 		}
 		return result;
 	}
@@ -1509,6 +1838,28 @@ public class SearchServiceImpl implements SearchService {
 		return booleanQuery;
 	}
 
+	private BooleanQuery queryProducts(String keyword, List<String> keywordFields, Boolean tokenized) {
+		BooleanQuery booleanQuery = new BooleanQuery();
+		if (!SearchUtils.isKeywordInvalid(keyword)) {
+			// 未指定搜索的字段,则采用默认搜索逻辑
+			if (CollectionUtils.isEmpty(keywordFields)) {
+//				booleanQuery.add(setGoodsBoost(keyword), BooleanClause.Occur.MUST);
+			} else {
+				BooleanQuery booleanQuery2 = new BooleanQuery();
+				for (String keywordField : keywordFields) {
+					// 是否分词
+					if (tokenized == null || !tokenized.booleanValue()) {
+						booleanQuery2.add(new TermQuery(new Term(keywordField, keyword.toLowerCase())), BooleanClause.Occur.SHOULD);
+					} else {
+						booleanQuery2.add(SearchUtils.getBooleanQuery(keywordField, keyword), BooleanClause.Occur.SHOULD);
+					}
+				}
+				booleanQuery.add(booleanQuery2, BooleanClause.Occur.MUST);
+			}
+		}
+		return booleanQuery;
+	}
+
 	/**
 	 * 同时搜索器件、类目、品牌等,并设置boost
 	 */
@@ -1575,7 +1926,7 @@ public class SearchServiceImpl implements SearchService {
         } catch (IOException e) {
             logger.error("", e);
         } finally {
-            SearchUtils.releaseIndexSearcher(indexSearcher);
+            releaseIndexSearcher(indexSearcher);
         }
         return result;
     }
@@ -1701,7 +2052,7 @@ public class SearchServiceImpl implements SearchService {
 		} catch (IOException e) {
 			logger.error("", e);
 		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+			releaseIndexSearcher(indexSearcher);
 		}
 		return products;
 	}
@@ -1741,7 +2092,7 @@ public class SearchServiceImpl implements SearchService {
 		} catch (IOException e) {
 			logger.error("", e);
 		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+			releaseIndexSearcher(indexSearcher);
 		}
 		return products;
 	}
@@ -1840,7 +2191,7 @@ public class SearchServiceImpl implements SearchService {
 			}
 			sPage.setContent(content);
 		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+			releaseIndexSearcher(indexSearcher);
 		}
 		return sPage;
 	}

+ 42 - 0
mall-search/src/main/java/com/uas/search/util/ObjectToDocumentUtils.java

@@ -115,11 +115,28 @@ public class ObjectToDocumentUtils {
         if (!StringUtils.isEmpty(product.getBrand())) {
             document.add(new StringField(SearchConstants.PRODUCT_PRIVATE_BRAND_FIELD, product.getBrand().toLowerCase(), Store.YES));
         }
+
+        String brandAndEnuu = "";
+        if (!StringUtils.isEmpty(product.getpBrandEn())) {
+			document.add(new StringField(SearchConstants.PRODUCT_PRIVATE_PBRAND_EN_FIELD, product.getpBrandEn().toLowerCase(), Store.YES));
+			brandAndEnuu += product.getpBrandEn();
+		}
+
+		if (!StringUtils.isEmpty(product.getpBrandCn())) {
+			document.add(new StringField(SearchConstants.PRODUCT_PRIVATE_PBRAND_CN_FIELD, product.getBrand().toLowerCase(), Store.YES));
+			brandAndEnuu += product.getpBrandCn();
+		}
+		if (!StringUtils.isEmpty(brandAndEnuu)) {
+			document.add(new StringField(SearchConstants.PRODUCT_PRIVATE_PBRAND_ENUU_FIELD, (brandAndEnuu + product.getEnUU()).toLowerCase(), Store.YES));
+		}
         if (!StringUtils.isEmpty(product.getCmpCode())) {
             document.add(new StringField(SearchConstants.PRODUCT_PRIVATE_CMPCODE_FIELD, product.getCmpCode().toLowerCase(), Store.YES));
         }
         if (!StringUtils.isEmpty(product.getKind())) {
             document.add(new StringField(SearchConstants.PRODUCT_PRIVATE_KIND_FIELD, product.getKind().toLowerCase(), Store.YES));
+			if (!StringUtils.isEmpty(product.getEnUU())) {
+				document.add(new StringField(SearchConstants.PRODUCT_PRIVATE_KIND_ENUU_FIELD, product.getKind().toLowerCase() + product.getEnUU(), Store.YES));
+			}
         }
         document.add(new StringField(SearchConstants.PRODUCT_PRIVATE_PBRANDEN_FIELD, product.getpBrandEn().toLowerCase(), Store.YES));
 		document.add(new StringField(SearchConstants.PRODUCT_PRIVATE_PCMPCODE_FIELD, product.getpCmpCode().toLowerCase(), Store.YES));
@@ -443,6 +460,31 @@ public class ObjectToDocumentUtils {
                 document.add(new StringField(SearchConstants.GOODS_PR_PCMPCODE_FIELD, products.getPcmpCode().toLowerCase(), Store.YES));
                 document.add(new BinaryDocValuesField(SearchConstants.GOODS_PR_PCMPCODE_FIELD, new BytesRef(products.getPcmpCode())));
             }
+            String brandAndStore = "";
+            if (products.getpBrandEn() != null) {
+                document.add(new TextField(SearchConstants.GOODS_PR_PBRAND_EN_FIELD, products.getpBrandEn(), Store.YES));
+                document.add(new StringField(SearchConstants.GOODS_PR_PBRAND_EN_UNTOKENIZED_FIELD, products.getpBrandEn().toLowerCase(), Store.YES));
+                document.add(new BinaryDocValuesField(SearchConstants.GOODS_PR_PBRAND_EN_UNTOKENIZED_FIELD, new BytesRef(products.getpBrandEn())));
+				brandAndStore += products.getpBrandEn();
+            }
+            if (products.getpBrandCn() != null) {
+                document.add(new TextField(SearchConstants.GOODS_PR_PBRAND_CN_FIELD, products.getpBrandCn(), Store.YES));
+                document.add(new StringField(SearchConstants.GOODS_PR_PBRAND_CN_UNTOKENIZED_FIELD, products.getpBrandCn().toLowerCase(), Store.YES));
+                document.add(new BinaryDocValuesField(SearchConstants.GOODS_PR_PBRAND_CN_UNTOKENIZED_FIELD, new BytesRef(products.getpBrandCn())));
+				brandAndStore += products.getpBrandEn();
+            }
+            if (!StringUtils.isEmpty(brandAndStore) && !StringUtils.isEmpty(goods.getStore()) && !StringUtils.isEmpty(goods.getStore().getUuid())) {
+				document.add(new StringField(SearchConstants.GOODS_PR_PBRAND_EN_CN_STUUID_UNTOKENIZED_FIELD, (brandAndStore + goods.getStore().getUuid()).toLowerCase(), Store.YES));
+			}
+
+            if (products.getKind() != null) {
+				document.add(new TextField(SearchConstants.GOODS_PR_KIND_FIELD, products.getKind(), Store.YES));
+				document.add(new StringField(SearchConstants.GOODS_PR_KIND_UNTOKENIZED_FIELD, products.getKind().toLowerCase(), Store.YES));
+				document.add(new BinaryDocValuesField(SearchConstants.GOODS_PR_KIND_UNTOKENIZED_FIELD, new BytesRef(products.getKind())));
+				if (!StringUtils.isEmpty(goods.getStore()) && !StringUtils.isEmpty(goods.getStore().getUuid())) {
+					document.add(new StringField(SearchConstants.GOODS_KIND_STUUID_UNTOKENIZED_FIELD, (products.getKind() + goods.getStore().getUuid()).toLowerCase(), Store.YES));
+				}
+			}
         }
 
         document.add(new StringField(SearchConstants.GOODS_PRIMARY_KEY_FIELD, primaryKey, Store.YES));

+ 6 - 0
mall-search/src/main/java/com/uas/search/util/SearchUtils.java

@@ -291,6 +291,8 @@ public class SearchUtils {
 	 *            页码
 	 * @param size
 	 *            页大小
+	 * @param duplicateFeild
+	 * 			  去重字段
 	 * @return
 	 */
 	public static SPage<Document> getDocuments(String tableName, Query query, Sort sort, Integer page, Integer size) throws IOException {
@@ -312,6 +314,10 @@ public class SearchUtils {
 		IndexSearcher indexSearcher = getIndexSearcher(tableName);
 
 		TopDocs topDocs;
+
+//		if (StringUtils.isEmpty(duplicateFeild)) {}
+		BooleanQuery booleanQuery = new BooleanQuery();
+		Query query1 = new MatchAllDocsQuery();
 		try {
 			// 如果页码不为1
 			if (sPage.getPage() > 1) {