如何在Hibernate Search中使用布尔运算符

时间:2012-04-19 00:51:53

标签: java hibernate-search

我正在学习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查询,但这是在hibernate搜索中使用布尔逻辑的正确方法吗? “should()”是否等同于“OR”(类似地,“must()”对应于“AND”)?

此外,以这种方式编写查询感觉很麻烦。例如,如果我有一个firstNames的集合可以匹配怎么办?这种类型的查询首先是DSL的良好匹配吗?

4 个答案:

答案 0 :(得分:3)

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

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

它可能感觉很麻烦,因为它是程序化的,并提供了许多详细的选项。更简单的替代方法是为查询使用简单字符串,并使用 QueryParser 创建查询。通常,解析器对解析用户输入很有用,程序化的解析器更容易处理明确定义的字段;例如,如果你有你提到的集合,很容易在 for 循环中构建它。

答案 1 :(得分:1)

回答第二个问题:

  

例如,如果我有一组firstNames要匹配,该怎么办?

我不是专家,但根据(结尾的第三个例子) 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();

并且,因此,Person s(firstName 最好“billy”或“bob”)AND(lastName =“thornton” ),虽然我认为它不会给比利鲍勃桑顿带来更高的分数; - )。

答案 2 :(得分:1)

您也可以使用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();

答案 3 :(得分:1)

我一直在寻找同样的问题,并且提出的问题有些不同。我正在寻找一个实际的OR交界处。如果结果没有通过这两个表达中的任何一个,但得分较低,那应该对我不起作用。我想完全省略这些结果。但是,您可以创建一个实际的布尔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();