我使用hibsearch构造了一个lucene查询,它返回包含(部分)搜索字符串的字符串值。其次,如果language id也匹配,并且deleted标志没有设置为true,那么查询必须只返回字符串值。我已经为此编写了下面的代码。但问题是它没有返回任何东西。
private Query getQueryWithBooleanClauses(Class entityClass, String searchString, Long preferredLanguageId, FullTextEntityManager fullTextEntityManager, String firstField, String... additionalFields) {
QueryBuilder queryBuilder = getQueryBuilder(entityClass, fullTextEntityManager);
Query containsSearchString = getMatchingStringCondition(searchString, queryBuilder, firstField, additionalFields);
BooleanQuery isPreferredOrDefaultLanguageTranslation = getLanguageCondition(preferredLanguageId);
BooleanQuery finalQuery = new BooleanQuery.Builder()
.add(new TermQuery(new Term("parentDeleted", "false")), BooleanClause.Occur.MUST)
.add(new TermQuery(new Term("parentApproved", "true")), BooleanClause.Occur.MUST)
.add(new TermQuery(new Term("childDeleted", "false")), BooleanClause.Occur.MUST)
.add(isPreferredOrDefaultLanguageTranslation, BooleanClause.Occur.MUST)
.add(containsSearchString, BooleanClause.Occur.MUST)
.build();
return finalQuery;
}
获取匹配字符串条件
private Query getMatchingStringCondition(String searchString, QueryBuilder queryBuilder, String firstField, String... additionalFields) {
log.info(MessageFormat.format("{0}*", searchString));
return queryBuilder.simpleQueryString()
.onFields(firstField, additionalFields)
.withAndAsDefaultOperator()
.matching(MessageFormat.format("{0}*", searchString))
.createQuery();
}
获取语言条件
private BooleanQuery getLanguageCondition(Long preferredLanguageId) {
return new BooleanQuery.Builder()
.add(createLanguagePredicate(preferredLanguageId), BooleanClause.Occur.SHOULD)
.add(createLanguagePredicate(languageService.getDefaultLanguage().getId()), BooleanClause.Occur.SHOULD)
.build();
}
创建语言 predicate
private Query createLanguagePredicate(Long languageId){
return new TermQuery(new Term("language.languageId", languageId.toString()));
}
查询执行方法
public List<AutoCompleteSuggestion> findAllBySearchStringAndDeletedIsFalse(Class entityClass, String searchString, Long preferredLanguageId){
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
Query finalQuery = getQueryWithBooleanClauses(entityClass, searchString, preferredLanguageId, fullTextEntityManager, "parent.latinName", "translatedName");
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(finalQuery, entityClass);
fullTextQuery.setProjection("parentId", "autoCompleteSuggestion", "childApproved"); //volgorde moet overeen komen met argumenten volgorde in AutoCompleteSuggestion constructor, zie convertToAutoCompleteSuggestionList
fullTextQuery.setMaxResults(maxResults);
fullTextQuery.getResultList();
return convertToAutoCompleteSuggestionList(fullTextQuery.getResultList());
}
这段代码不会抛出错误,但也不会返回任何结果。只有当我删除布尔和数值字段的所有布尔条件,只留下containsSearchString
条件时,查询才会返回任何结果。
根据这篇文章Hibernate Search 5.0 Numeric Lucene Query HSEARCH000233 issue,发生这种情况是因为到Hibernate搜索时,5个数字字段不再被视为文本字段,您不能对数字字段执行匹配查询。
您可以通过使用@FieldBridge
对字段进行注解来强制将其视为文本字段。但我不想这样做。因此我的问题是:如何对布尔值、日期和数字等非文本字段执行匹配查询?
EDIT:如果我用@FieldBridge
(impl= implementation.class)'注解过滤所需的所有字段,并且index参数必须总是设置为YES,那么它就可以工作。
但是现在所有这些字段都将被存储为字符串,这是不希望的。所以我仍然想知道是否有另一种更优雅的方法来应用过滤器。
编辑2:
@yrodiere,当我从languageId
中删除@FieldBridge(impl = LongBridge.class)
并将行.add(isPreferredOrDefaultLanguageTranslation, BooleanClause.Occur.MUST)
替换为:.add(queryBuilder.bool().must(queryBuilder.keyword().onField("language.languageId").matching(languageService.getDefaultLanguage().getId().toString()).createQuery()).createQuery(), BooleanClause.Occur.MUST)
我得到的错误:
org.hibernate.search.exception.SearchException: HSEARCH000238: Cannot create numeric range query for field 'language.languageId', since values are not numeric (Date, int, long, short or double)
但是刚才我发现matching()
也接受一个Long
的数字,所以我不需要在它上面调用toString()
。当matching()
使用Long
的值时,我没有得到错误,也没有返回任何东西。
只有当我使用new TermQuery(new Term("language.languageId", languageId.toString()))
而不是matching()
,同时使用LongBridge
作为languageId
时,才会返回任何内容。我是否定义了错误的matching()
查询?
我也有一个不同的问题,我想开始一个新的SO问题。但也许你可以回答这个问题,以及在这个线程:)。这个问题是关于@IndexedEmbedded
的includeEmbeddedObjectId
参数。我想我知道这是什么,但我希望有一些确认从你。
我假设当我将其设置为true
时,父实体的id将包含在子实体的lucene文档中,正确吗?假设此父实体用于matching()
查询中,该查询用作true/false
条件。那么,假设搜索将更快,因为现在也可以在子实体的lucene文档中找到id,这是正确的吗?
谢谢
1条答案
按热度按时间nafvub8i1#
在Hibernate Search 5中,布尔值仍然作为字符串进行索引。请参见
org.hibernate.search.bridge.builtin.BooleanBridge
。因此,布尔字段不是这里问题的一部分。如果你真的想自己创建数字查询,那么在Hibernate Search 5中,你必须使用数字范围查询,例如:
也就是说,为了避免这类问题,应该使用Hibernate Search DSL,然后传递模型中使用的类型的值(这里是
Long
),Hibernate Search将自动创建正确的查询。或者更好的方法是升级到Hibernate Search 6,它公开了一个不同的API,但不那么冗长,也不那么古怪。请参阅Hibernate Search 6中的Search DSL文档,特别是 predicate DSL。