【问题标题】:Boolean queries in Hibernate SearchHibernate Search 中的布尔查询
【发布时间】:2014-10-18 17:48:54
【问题描述】:

我正在尝试理解 Hibernate Search 中的一般查询。我在理解 forEntity(...) 方法时遇到了一些麻烦。文档是这样说的:

让我们看看如何使用 API。您首先需要创建一个附加到给定索引实体类型的查询构建器。这个 QueryBuilder 将知道使用什么分析器和应用什么字段桥。您可以创建多个 QueryBuilder(一个用于查询根中涉及的每种实体类型)。您从 SearchFactory 获得 QueryBuilder。

发件人:5.1.2. Building a Lucene query with the Hibernate Search query DSL

QueryBuilder mythQB = searchFactory.buildQueryBuilder().forEntity( Myth.class ).get();

从上面你看到你必须命名一个实体。当您想创建自己的查询构建器以在“根”查询中创建布尔查询时,您应该怎么做?你也应该绑定什么?

假设我想要一个应该匹配“Apples”或“Pie”的布尔查询。那是两个不同的实体,所以目前我有两个不同的查询构建器。但我需要第三个来创建布尔查询。这应该绑定到Object 类吗?

【问题讨论】:

    标签: java hibernate jakarta-ee lucene hibernate-search


    【解决方案1】:

    如果您希望能够从单个查询中返回多个实体,您可以使用您所说的 QueryBuilder,但您需要在 createFullTextQuery 调用中指定多个实体。例如,如果您有一个Book 实体和一个Movie 实体,并且想要查找标题以d 开头的所有书籍和电影,则可以使用以下查询:

    QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Book.class).get();
    Query query = queryBuilder.keyword().wildcard().onField("title").matching("d*").createQuery();
    org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery(query, Book.class, Movie.class);
    

    请注意,查询构建器仅使用Book 实体创建,但Books 和Movies 都在createFullTextQuery 调用中指定。

    【讨论】:

    • 但是forEntity 会做什么呢?如果它没有任何区别,为什么首先要有它呢?一定是有目的的?
    • forEntity 用于(如 Javadoc 中所述)确定要使用的分析器/字段桥接器并验证字段名称。似乎打算将 forEntities 方法添加到 QueryContextBuilder (在接口中有一个 TODO 提到了很多),但它尚未实现(截至 4.5.0)。
    • 那么这个答案是不是错了? Movie 没有与 Book 相同的场桥和分析器,所以它会失败?还是我不明白的地方?
    • 我成功地测试了这个,Book 有一个自定义分析器定义,Movie 没有那个定义。
    • 我可能应该补充一点,您也可以完全避免使用 QueryBuilder,方法是使用 Lucene API 直接创建一个 Query 对象,然后将该查询对象与您希望的类一起传递给 createFullTextQuery搜索/返回。
    【解决方案2】:

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

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

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

    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();
    

    【讨论】:

    • 我不是专家,但根据(第三个例子)5.1.2.1。 Hibernate Search Documentation 中的关键字查询,您应该能够像这样构建查询:
    • 并且,因此,有(名字最好是“billy”或“bob”)和(lastName =“thornton”)的人,虽然我不认为它会给人带来好处比利鲍勃松顿得分更高;-)。
    • 我不确定这是否能回答我的问题。 forEntity 里面的类在做什么?为什么有它?
    猜你喜欢
    • 1970-01-01
    • 2014-11-16
    • 2019-08-11
    • 2017-01-24
    • 1970-01-01
    • 2011-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多