Explorar o código

提升获取属性值联想词的速度;简化器件、类目、品牌搜索

sunyj %!s(int64=9) %!d(string=hai) anos
pai
achega
50f0d43b95

+ 106 - 245
search-console/src/main/java/com/uas/search/console/service/impl/SearchServiceImpl.java

@@ -10,9 +10,6 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.log4j.Logger;
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.TokenStream;
-import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.BooleanClause;
@@ -25,7 +22,6 @@ import org.apache.lucene.search.TopDocs;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
-import org.wltea.analyzer.lucene.IKAnalyzer;
 
 import com.alibaba.fastjson.JSONObject;
 import com.uas.search.console.core.util.FastjsonUtils;
@@ -57,137 +53,84 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 
 	@Override
 	public List<Long> getKindIds(String keyword) {
-		String message = "";
 		if (SearchUtils.isKeywordInvalid(keyword)) {
-			message = "搜索关键词无效:" + keyword;
-			logger.error(message);
-			throw new SearchException(message);
+			throw new SearchException("搜索关键词无效:" + keyword);
 		}
-		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
-
 		List<Long> ids = new ArrayList<Long>();
-		try {
-			BooleanQuery booleanQuery = getBooleanQuery(SearchConstants.KIND_NAMECN_FIELD, keyword);
-			logger.info(booleanQuery);
-			TopDocs hits = indexSearcher.search(booleanQuery, SearchConstants.TOP_NUM);
-			ScoreDoc[] scoreDocs = hits.scoreDocs;
-			for (ScoreDoc scoreDoc : scoreDocs) {
-				Set<String> fieldsToLoad = new HashSet<>();
-				fieldsToLoad.add(SearchConstants.KIND_ID_FIELD);
-				Document document = indexSearcher.doc(scoreDoc.doc, fieldsToLoad);
-				ids.add(Long.parseLong(document.get(SearchConstants.KIND_ID_FIELD)));
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+		BooleanQuery booleanQuery = SearchUtils.getBooleanQuery(SearchConstants.KIND_NAMECN_FIELD, keyword);
+		logger.info(booleanQuery);
+		List<Document> documents = SearchUtils.getDocuments(booleanQuery);
+		for (Document document : documents) {
+			ids.add(Long.parseLong(document.get(SearchConstants.KIND_ID_FIELD)));
 		}
 		return ids;
 	}
 
 	@Override
 	public List<Map<String, Object>> getKinds(String keyword) {
-		String message = "";
 		if (SearchUtils.isKeywordInvalid(keyword)) {
-			message = "搜索关键词无效:" + keyword;
-			logger.error(message);
-			throw new SearchException(message);
+			throw new SearchException("搜索关键词无效:" + keyword);
 		}
-		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
-
 		List<Map<String, Object>> kinds = new ArrayList<Map<String, Object>>();
-		try {
-			BooleanQuery booleanQuery = getBooleanQuery(SearchConstants.KIND_NAMECN_FIELD, keyword);
-			logger.info(booleanQuery);
-			TopDocs hits = indexSearcher.search(booleanQuery, SearchConstants.TOP_NUM);
-			ScoreDoc[] scoreDocs = hits.scoreDocs;
-			for (ScoreDoc doc : scoreDocs) {
-				Document document = indexSearcher.doc(doc.doc);
-				Map<String, Object> kind = new HashMap<String, Object>();
-				kind.put("id", Long.parseLong(document.get(SearchConstants.KIND_ID_FIELD)));
-				kind.put("nameCn", document.get(SearchConstants.KIND_NAMECN_FIELD));
-				kinds.add(kind);
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+		BooleanQuery booleanQuery = SearchUtils.getBooleanQuery(SearchConstants.KIND_NAMECN_FIELD, keyword);
+		logger.info(booleanQuery);
+		List<Document> documents = SearchUtils.getDocuments(booleanQuery);
+		for (Document document : documents) {
+			Map<String, Object> kind = new HashMap<String, Object>();
+			kind.put("id", Long.parseLong(document.get(SearchConstants.KIND_ID_FIELD)));
+			kind.put("nameCn", document.get(SearchConstants.KIND_NAMECN_FIELD));
+			kinds.add(kind);
 		}
 		return kinds;
 	}
 
 	@Override
 	public List<Long> getBrandIds(String keyword) {
-		String message = "";
 		if (SearchUtils.isKeywordInvalid(keyword)) {
-			message = "搜索关键词无效:" + keyword;
-			logger.error(message);
-			throw new SearchException(message);
+			throw new SearchException("搜索关键词无效:" + keyword);
 		}
-		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
-
 		List<Long> ids = new ArrayList<Long>();
-		try {
-			BooleanQuery booleanQuery = new BooleanQuery();
-			booleanQuery.add(getBooleanQuery(SearchConstants.BRAND_NAMECN_FIELD, keyword), BooleanClause.Occur.SHOULD);
-			booleanQuery.add(getBooleanQuery(SearchConstants.BRAND_NAMEEN_FIELD, keyword), BooleanClause.Occur.SHOULD);
-			logger.info(booleanQuery);
-
-			TopDocs hits = indexSearcher.search(booleanQuery, SearchConstants.TOP_NUM);
-			ScoreDoc[] scoreDocs = hits.scoreDocs;
-			for (ScoreDoc scoreDoc : scoreDocs) {
-				Set<String> fieldsToLoad = new HashSet<>();
-				fieldsToLoad.add(SearchConstants.BRAND_ID_FIELD);
-				Document document = indexSearcher.doc(scoreDoc.doc, fieldsToLoad);
-				ids.add(Long.parseLong(document.get(SearchConstants.BRAND_ID_FIELD)));
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+		BooleanQuery booleanQuery = new BooleanQuery();
+		booleanQuery.add(SearchUtils.getBooleanQuery(SearchConstants.BRAND_NAMECN_FIELD, keyword),
+				BooleanClause.Occur.SHOULD);
+		booleanQuery.add(SearchUtils.getBooleanQuery(SearchConstants.BRAND_NAMEEN_FIELD, keyword),
+				BooleanClause.Occur.SHOULD);
+		logger.info(booleanQuery);
+		List<Document> documents = SearchUtils.getDocuments(booleanQuery);
+		for (Document document : documents) {
+			ids.add(Long.parseLong(document.get(SearchConstants.BRAND_ID_FIELD)));
 		}
-
 		return ids;
 	}
 
 	@Override
 	public List<Map<String, Object>> getBrands(String keyword) {
-		String message = "";
 		if (SearchUtils.isKeywordInvalid(keyword)) {
-			message = "搜索关键词无效:" + keyword;
-			logger.error(message);
-			throw new SearchException(message);
+			throw new SearchException("搜索关键词无效:" + keyword);
 		}
-		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
-
 		List<Map<String, Object>> brands = new ArrayList<Map<String, Object>>();
-		try {
-			BooleanQuery booleanQuery = new BooleanQuery();
-			booleanQuery.add(getBooleanQuery(SearchConstants.BRAND_NAMECN_FIELD, keyword), BooleanClause.Occur.SHOULD);
-			booleanQuery.add(getBooleanQuery(SearchConstants.BRAND_NAMEEN_FIELD, keyword), BooleanClause.Occur.SHOULD);
-			logger.info(booleanQuery);
-
-			TopDocs hits = indexSearcher.search(booleanQuery, SearchConstants.TOP_NUM);
-			ScoreDoc[] scoreDocs = hits.scoreDocs;
-			for (ScoreDoc doc : scoreDocs) {
-				Document document = indexSearcher.doc(doc.doc);
-				Map<String, Object> brand = new HashMap<String, Object>();
-				brand.put("id", Long.parseLong(document.get(SearchConstants.BRAND_ID_FIELD)));
-				brand.put("uuid", document.get(SearchConstants.BRAND_UUID_FIELD));
-				brand.put("nameCn", document.get(SearchConstants.BRAND_NAMECN_FIELD));
-				brand.put("nameEn", document.get(SearchConstants.BRAND_NAMEEN_FIELD));
-				brands.add(brand);
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+		BooleanQuery booleanQuery = new BooleanQuery();
+		booleanQuery.add(SearchUtils.getBooleanQuery(SearchConstants.BRAND_NAMECN_FIELD, keyword),
+				BooleanClause.Occur.SHOULD);
+		booleanQuery.add(SearchUtils.getBooleanQuery(SearchConstants.BRAND_NAMEEN_FIELD, keyword),
+				BooleanClause.Occur.SHOULD);
+		logger.info(booleanQuery);
+		List<Document> documents = SearchUtils.getDocuments(booleanQuery);
+		for (Document document : documents) {
+			Map<String, Object> brand = new HashMap<String, Object>();
+			brand.put("id", Long.parseLong(document.get(SearchConstants.BRAND_ID_FIELD)));
+			brand.put("uuid", document.get(SearchConstants.BRAND_UUID_FIELD));
+			brand.put("nameCn", document.get(SearchConstants.BRAND_NAMECN_FIELD));
+			brand.put("nameEn", document.get(SearchConstants.BRAND_NAMEEN_FIELD));
+			brands.add(brand);
 		}
 		return brands;
 	}
 
 	@Override
 	public Map<String, Object> getComponentIds(String keyword, PageParams page) {
+		// 因为器件、属性值的数据量远比类目、品牌大得多,而且器件搜索可能还需进行分页,
+		// 所以涉及器件、属性值的搜索,都不能像类目和品牌一样直接利用SearchUtils.getDocuments方法
 		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
 
 		if (page == null) {
@@ -252,6 +195,7 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 
 			ScoreDoc[] scoreDocs = hits.scoreDocs;
 			for (ScoreDoc scoreDoc : scoreDocs) {
+				// 数据量太大,需要指定将获取的数据(以免载入不必要的数据,降低速度)
 				Set<String> fieldsToLoad = new HashSet<>();
 				fieldsToLoad.add(SearchConstants.COMPONENT_ID_FIELD);
 				Document document = indexSearcher.doc(scoreDoc.doc, fieldsToLoad);
@@ -272,11 +216,8 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 
 	@Override
 	public Set<Long> getKindIdsBySearchComponent(String keyword, String brandId) {
-		String message = "";
 		if (SearchUtils.isKeywordInvalid(keyword)) {
-			message = "搜索关键词无效:" + keyword;
-			logger.error(message);
-			throw new SearchException(message);
+			throw new SearchException("搜索关键词无效:" + keyword);
 		}
 		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
 
@@ -324,28 +265,18 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 			return kinds;
 		}
 
-		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
 		BooleanQuery booleanQuery = new BooleanQuery();
 		for (Long kindId : kindIds) {
 			booleanQuery.add(new TermQuery(new Term(SearchConstants.KIND_ID_FIELD, String.valueOf(kindId))),
 					BooleanClause.Occur.SHOULD);
 		}
-		try {
-			TopDocs topDocs = indexSearcher.search(booleanQuery, SearchConstants.TOP_NUM);
-			ScoreDoc[] scoreDocs = topDocs.scoreDocs;
-			for (ScoreDoc scoreDoc : scoreDocs) {
-				Document document = indexSearcher.doc(scoreDoc.doc);
-				Map<String, Object> kind = new HashMap<String, Object>();
-				kind.put("id", Long.parseLong(document.get(SearchConstants.KIND_ID_FIELD)));
-				kind.put("nameCn", document.get(SearchConstants.KIND_NAMECN_FIELD));
-				kinds.add(kind);
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+		List<Document> documents = SearchUtils.getDocuments(booleanQuery);
+		for (Document document : documents) {
+			Map<String, Object> kind = new HashMap<String, Object>();
+			kind.put("id", Long.parseLong(document.get(SearchConstants.KIND_ID_FIELD)));
+			kind.put("nameCn", document.get(SearchConstants.KIND_NAMECN_FIELD));
+			kinds.add(kind);
 		}
-
 		return kinds;
 	}
 
@@ -403,29 +334,19 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 			return brands;
 		}
 
-		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
 		BooleanQuery booleanQuery = new BooleanQuery();
 		for (Long brandId : brandIds) {
 			booleanQuery.add(new TermQuery(new Term(SearchConstants.BRAND_ID_FIELD, String.valueOf(brandId))),
 					BooleanClause.Occur.SHOULD);
 		}
-		try {
-			TopDocs topDocs = indexSearcher.search(booleanQuery, SearchConstants.TOP_NUM);
-			ScoreDoc[] scoreDocs = topDocs.scoreDocs;
-			for (ScoreDoc scoreDoc : scoreDocs) {
-				Document document = indexSearcher.doc(scoreDoc.doc);
-				Map<String, Object> brand = new HashMap<String, Object>();
-				brand.put("id", Long.parseLong(document.get(SearchConstants.BRAND_ID_FIELD)));
-				brand.put("uuid", document.get(SearchConstants.BRAND_UUID_FIELD));
-				brand.put("nameCn", document.get(SearchConstants.BRAND_NAMECN_FIELD));
-				brands.add(brand);
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+		List<Document> documents = SearchUtils.getDocuments(booleanQuery);
+		for (Document document : documents) {
+			Map<String, Object> brand = new HashMap<String, Object>();
+			brand.put("id", Long.parseLong(document.get(SearchConstants.BRAND_ID_FIELD)));
+			brand.put("uuid", document.get(SearchConstants.BRAND_UUID_FIELD));
+			brand.put("nameCn", document.get(SearchConstants.BRAND_NAMECN_FIELD));
+			brands.add(brand);
 		}
-
 		return brands;
 	}
 
@@ -468,11 +389,8 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 
 	@Override
 	public List<Map<String, Object>> getSimilarComponents(String componentCode) {
-		String message = "";
 		if (SearchUtils.isKeywordInvalid(componentCode)) {
-			message = "输入无效:" + componentCode;
-			logger.error(message);
-			throw new SearchException(message);
+			throw new SearchException("输入无效:" + componentCode);
 		}
 		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
 
@@ -505,45 +423,32 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 
 	@Override
 	public List<Map<String, Object>> getSimilarBrands(String brandName) {
-		String message = "";
 		if (SearchUtils.isKeywordInvalid(brandName)) {
-			message = "输入无效:" + brandName;
-			logger.error(message);
-			throw new SearchException(message);
+			throw new SearchException("输入无效:" + brandName);
 		}
-		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
-
 		List<Map<String, Object>> brands = new ArrayList<Map<String, Object>>();
 		// 品牌名称带有空格,并且中英文名并无一定顺序,因此对nameCn、nameEn均要搜索
-		try {
-			BooleanQuery booleanQuery = new BooleanQuery();
-			logger.info(booleanQuery);
-			String[] keywords = brandName.split(" ");
-			for (String keyword : keywords) {
-				// 搜索nameCn
-				booleanQuery.add(getBooleanQuery(SearchConstants.BRAND_NAMECN_FIELD, keyword),
-						BooleanClause.Occur.SHOULD);
-				// 搜索nameEn
-				booleanQuery.add(getBooleanQuery(SearchConstants.BRAND_NAMEEN_FIELD, keyword),
-						BooleanClause.Occur.SHOULD);
-			}
-			logger.info(booleanQuery);
+		BooleanQuery booleanQuery = new BooleanQuery();
+		logger.info(booleanQuery);
+		String[] keywords = brandName.split(" ");
+		for (String keyword : keywords) {
+			// 搜索nameCn
+			booleanQuery.add(SearchUtils.getBooleanQuery(SearchConstants.BRAND_NAMECN_FIELD, keyword),
+					BooleanClause.Occur.SHOULD);
+			// 搜索nameEn
+			booleanQuery.add(SearchUtils.getBooleanQuery(SearchConstants.BRAND_NAMEEN_FIELD, keyword),
+					BooleanClause.Occur.SHOULD);
+		}
+		logger.info(booleanQuery);
 
-			TopDocs hits = indexSearcher.search(booleanQuery, SIMILAR_NUM);
-			ScoreDoc[] scoreDocs = hits.scoreDocs;
-			for (ScoreDoc scoreDoc : scoreDocs) {
-				Document document = indexSearcher.doc(scoreDoc.doc);
-				Map<String, Object> brand = new HashMap<>();
-				brand.put("id", Long.parseLong(document.get(SearchConstants.BRAND_ID_FIELD)));
-				brand.put("uuid", document.get(SearchConstants.BRAND_UUID_FIELD));
-				brand.put("nameCn", document.get(SearchConstants.BRAND_NAMECN_FIELD));
-				brand.put("nameEn", document.get(SearchConstants.BRAND_NAMEEN_FIELD));
-				brands.add(brand);
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+		List<Document> documents = SearchUtils.getDocuments(booleanQuery, SIMILAR_NUM);
+		for (Document document : documents) {
+			Map<String, Object> brand = new HashMap<>();
+			brand.put("id", Long.parseLong(document.get(SearchConstants.BRAND_ID_FIELD)));
+			brand.put("uuid", document.get(SearchConstants.BRAND_UUID_FIELD));
+			brand.put("nameCn", document.get(SearchConstants.BRAND_NAMECN_FIELD));
+			brand.put("nameEn", document.get(SearchConstants.BRAND_NAMEEN_FIELD));
+			brands.add(brand);
 		}
 		return brands;
 	}
@@ -575,44 +480,32 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 	 * @return
 	 */
 	private List<Map<String, Object>> getSimilarKinds(String kindName, Short isLeaf, Short level) {
-		String message = "";
 		if (SearchUtils.isKeywordInvalid(kindName)) {
-			message = "输入无效:" + kindName;
-			logger.error(message);
-			throw new SearchException(message);
+			throw new SearchException("输入无效:" + kindName);
 		}
-		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
-
 		List<Map<String, Object>> kinds = new ArrayList<>();
-		try {
-			BooleanQuery booleanQuery = new BooleanQuery();
-			booleanQuery.add(getBooleanQuery(SearchConstants.KIND_NAMECN_FIELD, kindName), BooleanClause.Occur.MUST);
+		BooleanQuery booleanQuery = new BooleanQuery();
+		booleanQuery.add(SearchUtils.getBooleanQuery(SearchConstants.KIND_NAMECN_FIELD, kindName),
+				BooleanClause.Occur.MUST);
 
-			if (isLeaf != null && isLeaf == 1) {
-				booleanQuery.add(new TermQuery(new Term(SearchConstants.KIND_ISLEAF_FIELD, String.valueOf(isLeaf))),
+		if (isLeaf != null && isLeaf == 1) {
+			booleanQuery.add(new TermQuery(new Term(SearchConstants.KIND_ISLEAF_FIELD, String.valueOf(isLeaf))),
+					BooleanClause.Occur.MUST);
+		} else {
+			if (level != null && level > 0) {
+				booleanQuery.add(new TermQuery(new Term(SearchConstants.KIND_LEVEL_FIELD, String.valueOf(level))),
 						BooleanClause.Occur.MUST);
-			} else {
-				if (level != null && level > 0) {
-					booleanQuery.add(new TermQuery(new Term(SearchConstants.KIND_LEVEL_FIELD, String.valueOf(level))),
-							BooleanClause.Occur.MUST);
-				}
 			}
-			logger.info(booleanQuery);
-			TopDocs hits = indexSearcher.search(booleanQuery, SIMILAR_NUM);
-			ScoreDoc[] scoreDocs = hits.scoreDocs;
-			for (ScoreDoc scoreDoc : scoreDocs) {
-				Document document = indexSearcher.doc(scoreDoc.doc);
-				Map<String, Object> map = new HashMap<>();
-				map.put("id", Long.parseLong(document.get(SearchConstants.KIND_ID_FIELD)));
-				map.put("nameCn", document.get(SearchConstants.KIND_NAMECN_FIELD));
-				map.put("isLeaf", Short.parseShort(document.get(SearchConstants.KIND_ISLEAF_FIELD)));
-				map.put("level", Short.parseShort(document.get(SearchConstants.KIND_LEVEL_FIELD)));
-				kinds.add(map);
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-		} finally {
-			SearchUtils.releaseIndexSearcher(indexSearcher);
+		}
+		logger.info(booleanQuery);
+		List<Document> documents = SearchUtils.getDocuments(booleanQuery, SIMILAR_NUM);
+		for (Document document : documents) {
+			Map<String, Object> map = new HashMap<>();
+			map.put("id", Long.parseLong(document.get(SearchConstants.KIND_ID_FIELD)));
+			map.put("nameCn", document.get(SearchConstants.KIND_NAMECN_FIELD));
+			map.put("isLeaf", Short.parseShort(document.get(SearchConstants.KIND_ISLEAF_FIELD)));
+			map.put("level", Short.parseShort(document.get(SearchConstants.KIND_LEVEL_FIELD)));
+			kinds.add(map);
 		}
 		return kinds;
 	}
@@ -620,11 +513,8 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 	@Override
 	public List<Map<String, String>> getSimilarPropertyValues(Long kindId, Long propertyId, String keyword,
 			Long topNum) {
-		String message = "";
 		if (kindId == null || propertyId == null) {
-			message = "类目id或属性id为空";
-			logger.error(message);
-			throw new SearchException(message);
+			throw new SearchException("类目id和属性id不能为空");
 		}
 		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
 
@@ -641,7 +531,6 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 		}
 
 		List<String> propertyValues = new ArrayList<>();
-
 		try {
 			BooleanQuery booleanQuery = new BooleanQuery();
 			booleanQuery.add(new TermQuery(new Term(SearchConstants.COMPONENT_KINDID_FIELD, String.valueOf(kindId))),
@@ -649,6 +538,7 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 			booleanQuery.add(new PrefixQuery(new Term(propertyIdString, keyword.toLowerCase())),
 					BooleanClause.Occur.MUST);
 			logger.info(booleanQuery);
+			// 如果只搜索topNum个结果,去除重复的属性值后,数目很可能是不够的
 			TopDocs topDocs = indexSearcher.search(booleanQuery, SearchConstants.TOP_NUM);
 			ScoreDoc[] scoreDocs = topDocs.scoreDocs;
 			for (ScoreDoc scoreDoc : scoreDocs) {
@@ -659,8 +549,10 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 				if (!StringUtils.isEmpty(propertyValue) && !propertyValues.contains(propertyValue)) {
 					propertyValues.add(propertyValue);
 				}
+				if (propertyValues.size() >= topNum) {
+					break;
+				}
 			}
-			removeElements(propertyValues, topNum.intValue());
 		} catch (IOException e) {
 			e.printStackTrace();
 		} finally {
@@ -740,17 +632,14 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 	 * @return
 	 */
 	private List<String> getSimilarValues(String field, String keyword) {
-		String message = "";
 		if (SearchUtils.isKeywordInvalid(keyword)) {
-			message = "输入无效:" + keyword;
-			logger.error(message);
-			throw new SearchException(message);
+			throw new SearchException("输入无效:" + keyword);
 		}
 		IndexSearcher indexSearcher = SearchUtils.getIndexSearcher();
 
 		List<String> result = new ArrayList<>();
 		try {
-			BooleanQuery booleanQuery = getBooleanQuery(field, keyword);
+			BooleanQuery booleanQuery = SearchUtils.getBooleanQuery(field, keyword);
 			logger.info(booleanQuery);
 			TopDocs hits = indexSearcher.search(booleanQuery, SIMILAR_NUM);
 			ScoreDoc[] scoreDocs = hits.scoreDocs;
@@ -768,34 +657,6 @@ public class SearchServiceImpl implements SearchService, InnerSearchService {
 		return result;
 	}
 
-	/**
-	 * 对搜索词进行分词后组合得到BooleanQuery
-	 * 
-	 * @param field
-	 * @param keyword
-	 * @return
-	 */
-	private BooleanQuery getBooleanQuery(String field, String keyword) {
-		if (StringUtils.isEmpty(field) || StringUtils.isEmpty(keyword)) {
-			return null;
-		}
-		BooleanQuery booleanQuery = new BooleanQuery();
-		@SuppressWarnings("resource")
-		Analyzer analyzer = new IKAnalyzer(true);
-		try {
-			TokenStream tokenStream = analyzer.tokenStream(field, keyword);
-			tokenStream.reset();
-			CharTermAttribute cta = tokenStream.addAttribute(CharTermAttribute.class);
-			while (tokenStream.incrementToken()) {
-				booleanQuery.add(new PrefixQuery(new Term(field, cta.toString())), BooleanClause.Occur.MUST);
-			}
-			tokenStream.close();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-		return booleanQuery;
-	}
-
 	/**
 	 * 删除lists内startIndex(含)后的元素
 	 * 

+ 49 - 3
search-console/src/main/java/com/uas/search/console/util/SearchUtils.java

@@ -13,6 +13,7 @@ import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.PrefixQuery;
+import org.apache.lucene.search.Query;
 import org.apache.lucene.search.ScoreDoc;
 import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.search.TopDocs;
@@ -113,20 +114,65 @@ public class SearchUtils {
 	 * @return Document列表
 	 */
 	public static List<Document> getDocuments(String field, String keyword) {
+		return getDocuments(field, keyword, SearchConstants.TOP_NUM);
+	}
+
+	/**
+	 * 根据域和搜索词获取指定数目的Document列表
+	 * 
+	 * @param field
+	 *            搜索域
+	 * @param keyword
+	 *            搜索词
+	 * @param topNum
+	 *            指定的数目(数目最多为该数目)
+	 * @return
+	 */
+	public static List<Document> getDocuments(String field, String keyword, int topNum) {
 		if (StringUtils.isEmpty(field) || StringUtils.isEmpty(keyword)) {
 			throw new SearchException("搜索的域和搜索词不能为空");
 		}
+		TermQuery termQuery = new TermQuery(new Term(field, keyword));
+		return getDocuments(termQuery, topNum);
+	}
+
+	/**
+	 * 根据查询条件获取Document列表
+	 * 
+	 * @param query
+	 *            查询条件
+	 * @return
+	 */
+	public static List<Document> getDocuments(Query query) {
+		return getDocuments(query, SearchConstants.TOP_NUM);
+	}
+
+	/**
+	 * 根据查询条件获取指定数目的Document列表
+	 * 
+	 * @param query
+	 *            查询条件
+	 * @param topNum
+	 *            指定的数目(数目最多为该数目)
+	 * @return
+	 */
+	public static List<Document> getDocuments(Query query, int topNum) {
+		if (query == null) {
+			throw new SearchException("query不能为null");
+		}
+		if (topNum < 1) {
+			throw new SearchException("查询的数目topNum不能小于1");
+		}
 		IndexSearcher indexSearcher = getIndexSearcher();
 		List<Document> documents = new ArrayList<>();
-		TermQuery termQuery = new TermQuery(new Term(field, String.valueOf(keyword)));
 		try {
-			TopDocs topDocs = indexSearcher.search(termQuery, SearchConstants.TOP_NUM);
+			TopDocs topDocs = indexSearcher.search(query, topNum);
 			ScoreDoc[] scoreDocs = topDocs.scoreDocs;
 			for (ScoreDoc scoreDoc : scoreDocs) {
 				documents.add(indexSearcher.doc(scoreDoc.doc));
 			}
 		} catch (IOException e) {
-			throw new SearchException(e);
+			throw new SearchException(e).setDetailedMessage(e);
 		} finally {
 			releaseIndexSearcher(indexSearcher);
 		}