8

我正在学习Hibernate Search Query DSL,但我不确定如何使用 AND 或 OR 等布尔参数构造查询。

例如,假设我要返回firstName值为“bill”或“bob”的所有人员记录。

在 hibernate 文档之后,一个示例使用带有两个子查询的 bool() 方法,例如:

QueryBuilder b = fts.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get();
Query luceneQuery = b.bool()
    .should(b.keyword().onField("firstName").matching("bill").createQuery())
    .should(b.keyword().onField("firstName").matching("bob").createQuery())
    .createQuery();

logger.debug("query 1:{}", luceneQuery.toString());

这最终会产生我想要的 lucene 查询,但这是在休眠搜索中使用布尔逻辑的正确方法吗?“should()”是否等同于“OR”(类似地,“must()”是否对应于“AND”)?

此外,以这种方式编写查询感觉很麻烦。例如,如果我有一组要匹配的名字怎么办?这种类型的查询首先是否适合 DSL?

4

4 回答 4

3

是的,你的例子是正确的。布尔运算符被称为should而不是OR,因为它们在 Lucene API 和文档中具有名称,并且因为它更合适:它不仅影响布尔决策,而且还影响结果的评分。

例如,如果您搜索“菲亚特品牌”或“蓝色”的汽车,菲亚特和蓝色品牌的汽车也将被返回,并且得分高于蓝色但不是菲亚特的汽车。

它可能会让人觉得很麻烦,因为它是程序化的并且提供了许多详细的选项。一个更简单的替代方法是为您的查询使用一个简单的字符串并使用QueryParser创建查询。一般来说,解析器对解析用户输入很有用,程序化的更容易处理定义好的字段;例如,如果您有您提到的集合,则很容易在for循环中构建它。

于 2012-04-25T19:54:31.033 回答
2

您也可以使用BooleanQuery。我更喜欢这个,因为您可以在列表的循环中使用它。

    org.hibernate.search.FullTextQuery hibque = null; 

    org.apache.lucene.search.BooleanQuery bquery = new BooleanQuery();

    QueryBuilder qb = fulltextsession.getSearchFactory().buildQueryBuilder()
              .forEntity(entity.getClass()).get();
    for (String keyword : list) {
        bquery.add(qb.keyword().wildcard().onField(entityColumn).matching(keyword)
              .createQuery()  , BooleanClause.Occur.SHOULD);
    }

    if (!filterColumn.equals("") && !filterValue.equals("")) {
       bquery.add(qb.keyword().wildcard().onField(column).matching(value).createQuery()
                        , BooleanClause.Occur.MUST);
    } 

    hibque = fulltextsession.createFullTextQuery(bquery, entity.getClass());

    int num = hibque.getResultSize();
于 2015-03-10T06:30:33.560 回答
1

回答你的第二个问题:

例如,如果我有一组要匹配的名字怎么办?

我不是专家,但根据(最后的第三个例子)5.1.2.1。Hibernate Search Documentation中的关键字查询,您应该能够像这样构建查询:

Collection<String> namesCollection = getNames(); // Contains "billy" and "bob", for example
StringBuilder names = new StringBuilder(100);
for(String name : namesCollection) {
    names.append(name).append(" "); // Never mind the space at the end of the resulting string.
}

QueryBuilder b = fts.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get();
Query luceneQuery = b.bool()
    .should(
        // Searches for multiple possible values in the same field
        b.keyword().onField("firstName").matching( sb.toString() ).createQuery()
    )
    .must(b.keyword().onField("lastName").matching("thornton").createQuery())
    .createQuery();

并且,因此,Persons 与(firstName 最好是“比利”或“鲍勃”)和(lastName=“桑顿”),虽然我不认为它会给好人比利鲍勃桑顿更高的分数 ;-)。

于 2012-11-24T08:09:16.667 回答
1

我一直在寻找相同的问题,但遇到的问题与提出的问题有所不同。我在寻找一个真正的OR交界处。should case 对我不起作用,因为结果没有通过两个表达式中的任何一个,但分数较低。我想完全忽略这些结果。但是,您可以使用禁用评分的单独布尔表达式创建实际的布尔 OR 表达式:

val booleanQuery = cb.bool();
val packSizeSubQuery = cb.bool();

packSizes.stream().map(packSize -> cb.phrase()
     .onField(LUCENE_FIELD_PACK_SIZES)
     .sentence(packSize.name())
     .createQuery())
     .forEach(packSizeSubQuery::should);

booleanQuery.must(packSizeSubQuery.createQuery()).disableScoring();
fullTextEntityManager.createFullTextQuery(booleanQuery.createQuery(), Product.class)
return persistenceQuery.getResultList();
于 2016-11-07T17:10:22.890 回答