Hibernate Search 查询搜索所有 table 而不是仅指定的 class' table

Hibernate Search query searches all tables instead of only the specified class' table

我有一个摘要 class ProductProductA, [=51] 子class =]ProductB 和 ProductC.
并且 classes ProductAProductBProductC 映射到数据库 tables PRODUCTS_A, PRODUCTS_BPRODUCTS_C分别。

现在我想通过 Hibernate Search 对 ProductA 实体执行全文搜索。
我写了一些代码来成功地从数据库中获取预期的 ProductA 实体,但我在日志中发现(如下)执行的 Hibernate Search 查询实际上搜索了所有 tables PRODUCTS_APRODUCTS_BPRODUCTS_C 而不是我预期的 table PRODUCTS_A

我只想获取 ProductA 个实体,为什么 ProductBPRODUCTS_C tables 也搜索过?有办法解决这个问题吗?

日志

从Hibernate输出的如下工作日志可以看出,除了PRODUCTS_Atable之外,还有PRODUCTS_BPRODUCTS_C table 也被搜索。


休眠:select this_.ID 作为 ID1_2_0_,this_.NAME 作为 NAME2_2_0_,this_.FEATURE 作为 FEATURE3_2_0_,this_.CREATED_DATE 作为 CREATED_4_2_0_,this_.MODIFIED_DATE 作为 MODIFIED5_2_0_,this_.FEATURE_A1 作为 FEATURE_1_3_0_,this_.FEATURE_A2 作为 FEATURE_2_3_0_,this_.FEATURE_B1 作为 FEATURE_1_4_0_,this_.FEATURE_B2 作为 FEATURE_2_4_0_,this_.FEATURE_C1 作为 FEATURE_1_5_0_,this_.FEATURE_C2 作为 FEATURE_2_5_0_, this_.clazz_ as clazz_0_ from ( select ID, NAME, FEATURE, CREATED_DATE, MODIFIED_DATE, FEATURE_A1, FEATURE_A2, null::varchar 作为 FEATURE_B1,null::varchar 作为 FEATURE_B2,null::varchar 作为 FEATURE_C1,null::varchar 作为 FEATURE_C2,1 作为 clazz_ from PRODUCTS_A union all select ID, NAME, FEATURE, CREATED_DATE, MODIFIED_DATE, null::varchar 作为 FEATURE_A1,null::varchar 作为 FEATURE_A2,FEATURE_B1,FEATURE_B2,null::varchar 作为 FEATURE_C1,null::varchar as FEATURE_C2, 2 as clazz_ from PRODUCTS_B union all select ID, NAME,特征,CREATED_DATE,MODIFIED_DATE,null::varchar 作为 FEATURE_A1,null::varchar 作为 FEATURE_A2,null::varchar 作为 FEATURE_B1, null::varchar as FEATURE_B2, FEATURE_C1, FEATURE_C2, 3 as clazz_ from PRODUCTS_C ) this_ where (this_.ID 在 (?))


代码

实体Classes

这是实体 classes Product, ProductA, ProductBProductC.


public abstract class Product {
    @Id
    protected Long id;

    @Field
    protected String name;

    @Field
    protected String feature;

    protected Date createdDate;

    protected Date modifiedDate;

    // Getters and setters...
}

@Entity
@Indexed
public class ProductA extends Product {
    @Field
    private String featureA1;

    @Field
    private String featureA2;

    public ProductA() {
    }

    // Getters and setters...
}

ProductBProductC classes 与 ProductA 相似class.


Hibernate 映射文件

Product.hbm.xml
union-subclass元素用来反映Productclass之间的subclass关系以及 ProductAProductBProductC classes.


<hibernate-mapping package="com.raychen518.study.hibernate">
    <class name="Product" abstract="true">
        <id name="id" column="ID">
            <generator class="increment" />
        </id>
        <property name="name" column="NAME" />
        <property name="feature" column="FEATURE" />
        <property name="createdDate" type="timestamp" column="CREATED_DATE" />
        <property name="modifiedDate" type="timestamp" column="MODIFIED_DATE" />
        <union-subclass name="ProductA" table="PRODUCTS_A">
            <property name="featureA1" column="FEATURE_A1" />
            <property name="featureA2" column="FEATURE_A2" />
        </union-subclass>
        <union-subclass name="ProductB" table="PRODUCTS_B">
            <property name="featureB1" column="FEATURE_B1" />
            <property name="featureB2" column="FEATURE_B2" />
        </union-subclass>
        <union-subclass name="ProductC" table="PRODUCTS_C">
            <property name="featureC1" column="FEATURE_C1" />
            <property name="featureC2" column="FEATURE_C2" />
        </union-subclass>
    </class>
</hibernate-mapping>

休眠配置文件

hibernate.cfg.xml


<hibernate-configuration>
    <session-factory>
        <property name="connection.driver_class">org.postgresql.Driver</property>
        <property name="connection.url">jdbc:postgresql://localhost:5432/test</property>
        <property name="connection.username">postgres</property>
        <property name="connection.password">admin</property>
        <property name="connection.pool_size">1</property>
        <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>

        <property name="current_session_context_class">thread</property>
        <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
        <property name="show_sql">true</property>
        <property name="hbm2ddl.auto">validate</property>

        <!-- Setting for Hibernate Search -->
        <property name="hibernate.search.lucene_version">LUCENE_CURRENT</property>
        <property name="hibernate.search.default.directory_provider">filesystem</property>
        <property name="hibernate.search.default.indexBase">hibernate.search.test/lucene/indexes</property>

        <mapping resource="Product.hbm.xml" />
    </session-factory>
</hibernate-configuration>

应用程序启动器Class

ProductManager class 包含主要方法,因此用作应用程序启动器。它启动 Hibernate 搜索索引进程,清除 PRODUCTS_APRODUCTS_BPRODUCTS_C tables 并向其中插入一些示例产品数据,最后使用 Hibernate Search 执行全文搜索。
令我困惑的是,我在以下语句 Query query = fullTextSession.createFullTextQuery(luceneQuery, ProductA.class); 在方法 searchProducts() 中。为什么 Hibernate Search 还搜索 ProductBProductC 实体?


public class ProductManager {

    public static void main(String[] args) throws InterruptedException {
        ProductManager productManager = new ProductManager();
        productManager.indexAllProducts();
        productManager.deleteAllProducts();
        productManager.generateSomeProducts();
        productManager.searchProducts();
    }

    private void indexAllProducts() throws InterruptedException {
        FullTextSession fullTextSession = Search.getFullTextSession(HibernateUtil.getSessionFactory().getCurrentSession());
        fullTextSession.createIndexer().startAndWait();
    }

    public void deleteAllProducts() {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        @SuppressWarnings("unchecked")
        List<Product> results = session.createQuery("from Product").list();

        for (Product result : results) {
            session.delete(result);
        }

        session.getTransaction().commit();
    }

    public void generateSomeProducts() {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        session.save(new ProductA("feature001", "featureA1001", "featureA2001", new Date()));
        session.save(new ProductA("feature002", "featureA1002", "featureA2002", new Date()));
        session.save(new ProductA("feature003", "featureA1003", "featureA2003", new Date()));

        session.save(new ProductB("feature001", "featureB1001", "featureB2001", new Date()));
        session.save(new ProductB("feature002", "featureB1002", "featureB2002", new Date()));
        session.save(new ProductB("feature003", "featureB1003", "featureB2003", new Date()));

        session.save(new ProductC("feature001", "featureC1001", "featureC2001", new Date()));
        session.save(new ProductC("feature002", "featureC1002", "featureC2002", new Date()));
        session.save(new ProductC("feature003", "featureC1003", "featureC2003", new Date()));

        session.getTransaction().commit();
    }

    private void searchProducts() {
        FullTextSession fullTextSession = Search.getFullTextSession(HibernateUtil.getSessionFactory().getCurrentSession());
        fullTextSession.beginTransaction();

        QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(ProductA.class).get();
        org.apache.lucene.search.Query luceneQuery = queryBuilder.keyword().onFields("feature").matching("feature002").createQuery();

        // Set the 2nd method parameter using "Product.class" to get products of the types ProductA, ProductB and ProductC.
        // Set the 2nd method parameter using "ProductA.class" to get products of the types ProductA.
        Query query = fullTextSession.createFullTextQuery(luceneQuery, ProductA.class);

        @SuppressWarnings("unchecked")
        List<Product> queryResults = query.list();
        for (Product queryResult : queryResults) {
            System.out.println("queryResult: " + queryResult);
        }

        fullTextSession.getTransaction().commit();
    }

}

我最近将其修复为 https://hibernate.atlassian.net/browse/HSEARCH-2301 另一个 Whosebug 问题。

它还没有发布,但是这个补丁相当小并且只本地化在一个文件中:https://github.com/hibernate/hibernate-search/pull/1122/files所以你应该能够在 5.5 分支上本地应用它。

使用https://patch-diff.githubusercontent.com/raw/hibernate/hibernate-search/pull/1122.diff获取原始差异文件。

更新 我们在 5.5 中修复了它。4.Final:http://in.relation.to/2016/06/29/Polishing-Polishing-And-More-Polishing-Hibernate-Search-5-5-4-Final/