【发布时间】:2017-10-02 07:19:45
【问题描述】:
我有一个 Lucene 索引,在 Hibernate Search 注释的帮助下通过 Hibernate 生成,有 3 个字段(只是为了简化一点)描述一篇文章:
id, title, brand
内容示例:
id, title, brand
1, "Long skirt", "Sweet and Gabbana"
2, "Sweet neck vest", "Armani"
3, "Sweet feeling shirt", "Armani"
注意“Sweet and Gabbana”、“甜美领口背心”和“Sweet feel shirt”如何共享“sweet”这个词。
我想做一个 Lucene 查询,如果我搜索关键字“sweet”,我会得到 2 个不同的类别,一个是标题,另一个是品牌。例如:
- Titles -> “甜颈背心”、“甜美感衬衫”
- 品牌 -> “Sweet and Gabbana”
换句话说,我想向用户展示系统在这两个不同的类别中找到结果。
当我运行查询(标题和品牌之间的一种 OR)时,我得到所有三个条目(在 Lucene 中,id 为 1、2 和 3 的文档),它们只包含一个属性或另一个属性,但是我如何对它们进行分类?
@PersistenceContext
private EntityManager em;
...
@Override
public List<ArticleByIndexModel> retrieveArticlesSearchQueryResult(final String searchString,
final String languageIso639) {
final FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
final org.apache.lucene.search.Query luceneQuery = buildUpArticlesSearchLuceneQuery(searchString,
languageIso639, fullTextEntityManager);
final String titleFieldName = ArticleTranslationFieldPrefixes.TITLE + languageIso639;
final String brandNameFieldName = BrandTaxonomy.BrandTaxonomyNameFieldName.NAME;
final FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(luceneQuery);
fullTextQuery.setMaxResults(50);
fullTextQuery.setProjection(Article_.articleID.getName(), titleFieldName, brandNameFieldName,
Article_.brandSku.getName(), FullTextQuery.DOCUMENT_ID, FullTextQuery.EXPLANATION, FullTextQuery.THIS);
@SuppressWarnings("unchecked")
final List<Object[]> list = (List<Object[]>) fullTextQuery.getResultList();
final List<ArticleByIndexModel> resultList = list.stream()
.map(x -> new ArticleByIndexModel((Integer) x[0], (String) x[1])).collect(Collectors.toList());
return resultList;
}
private org.apache.lucene.search.Query buildUpArticlesSearchLuceneQuery(final String searchString,
final String languageIso639, final FullTextEntityManager fullTextEntityManager) {
final String brandSkuName = Article_.brandSku.getName();
final String analyzerPartName = ArticleTranslationDiscriminator.getAnalyzerPartNameByLanguage(languageIso639);
final String titleFieldName = ArticleTranslationFieldPrefixes.TITLE + languageIso639;
final String titleEdgeNGramFieldName = ArticleTranslationFieldPrefixes.TITLE_EDGE_N_GRAM + languageIso639;
final String titleNGramFieldName = ArticleTranslationFieldPrefixes.TITLE_N_GRAM + languageIso639;
final String brandNameEdgeNGramFieldName = BrandTaxonomy.BrandTaxonomyNameFieldName.NAME_EDGE_N_GRAM;
final String brandNameNGramFieldName = BrandTaxonomy.BrandTaxonomyNameFieldName.NAME_N_GRAM;
final SearchFactory searchFactory = fullTextEntityManager.getSearchFactory();
final QueryBuilder qb = searchFactory.buildQueryBuilder().forEntity(Article.class)
.overridesForField(titleFieldName, ArticleTranslationFieldPrefixes.TITLE + analyzerPartName)
.overridesForField(titleEdgeNGramFieldName,
ArticleTranslationFieldPrefixes.TITLE_EDGE_N_GRAM + analyzerPartName)
.overridesForField(titleNGramFieldName, ArticleTranslationFieldPrefixes.TITLE_N_GRAM + analyzerPartName)
.get();
final org.apache.lucene.search.Query luceneQuery =
/**/
qb.bool()
/**/
.should(qb.phrase().withSlop(2).onField(titleNGramFieldName).andField(titleEdgeNGramFieldName)
.boostedTo(5).sentence(searchString.toLowerCase()).createQuery())
/**/
.should(qb.phrase().withSlop(2).onField(brandNameNGramFieldName)
.andField(brandNameEdgeNGramFieldName).boostedTo(5).sentence(searchString.toLowerCase())
.createQuery())
/**/
.should(qb.keyword().onField(brandSkuName).matching(searchString.toLowerCase()).createQuery())
/**/
.createQuery();
return luceneQuery;
}
我认为在进行 2 个不同的查询然后合并结果方面没有任何解决方案。
我读到了 Facets,但我认为它们不适合这种情况。
你有什么想法吗?
谢谢!!!
【问题讨论】:
-
为什么不只进行一次查询,然后遍历结果并自己创建类别?我认为即使 lucene 有这种东西(某种分组),它也会这样做......
-
无关说明:您可能不想在
FullTextQuery.DOCUMENT_ID上进行投影,因为这是一个内部 ID,与您的实体 ID 不同。请改用FullTextQuery.ID。 -
@Yossy,我不能按照你的建议做,因为我在问题中报告的查询返回了所有文档,然后无法按类别对结果进行分组(除非我使用某种结果的模式匹配)。约安。是的,我知道。你是对的。
标签: java hibernate lucene hibernate-search