Hibernate Search 查询搜索所有 table 而不是仅指定的 class' table
Hibernate Search query searches all tables instead of only the specified class' table
我有一个摘要 class Product 由 ProductA, [=51] 子class =]ProductB 和 ProductC.
并且 classes ProductA、ProductB 和 ProductC 映射到数据库 tables PRODUCTS_A, PRODUCTS_B 和 PRODUCTS_C分别。
现在我想通过 Hibernate Search 对 ProductA 实体执行全文搜索。
我写了一些代码来成功地从数据库中获取预期的 ProductA 实体,但我在日志中发现(如下)执行的 Hibernate Search 查询实际上搜索了所有 tables PRODUCTS_A、PRODUCTS_B 和 PRODUCTS_C 而不是我预期的 table PRODUCTS_A。
我只想获取 ProductA 个实体,为什么 ProductB 和 PRODUCTS_C tables 也搜索过?有办法解决这个问题吗?
日志
从Hibernate输出的如下工作日志可以看出,除了PRODUCTS_Atable之外,还有PRODUCTS_B 和 PRODUCTS_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, ProductB和 ProductC.
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...
}
ProductB 和 ProductC classes 与 ProductA 相似class.
Hibernate 映射文件
Product.hbm.xml
union-subclass元素用来反映Productclass之间的subclass关系以及 ProductA、ProductB 和 ProductC 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_A、PRODUCTS_B 和 PRODUCTS_C tables 并向其中插入一些示例产品数据,最后使用 Hibernate Search 执行全文搜索。
令我困惑的是,我在以下语句 Query query = fullTextSession.createFullTextQuery(luceneQuery, ProductA.class); 在方法 searchProducts() 中。为什么 Hibernate Search 还搜索 ProductB 和 ProductC 实体?
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/
我有一个摘要 class Product 由 ProductA, [=51] 子class =]ProductB 和 ProductC.
并且 classes ProductA、ProductB 和 ProductC 映射到数据库 tables PRODUCTS_A, PRODUCTS_B 和 PRODUCTS_C分别。
现在我想通过 Hibernate Search 对 ProductA 实体执行全文搜索。
我写了一些代码来成功地从数据库中获取预期的 ProductA 实体,但我在日志中发现(如下)执行的 Hibernate Search 查询实际上搜索了所有 tables PRODUCTS_A、PRODUCTS_B 和 PRODUCTS_C 而不是我预期的 table PRODUCTS_A。
我只想获取 ProductA 个实体,为什么 ProductB 和 PRODUCTS_C tables 也搜索过?有办法解决这个问题吗?
日志
从Hibernate输出的如下工作日志可以看出,除了PRODUCTS_Atable之外,还有PRODUCTS_B 和 PRODUCTS_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, ProductB和 ProductC.
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...
}
ProductB 和 ProductC classes 与 ProductA 相似class.
Hibernate 映射文件
Product.hbm.xml
union-subclass元素用来反映Productclass之间的subclass关系以及 ProductA、ProductB 和 ProductC 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_A、PRODUCTS_B 和 PRODUCTS_C tables 并向其中插入一些示例产品数据,最后使用 Hibernate Search 执行全文搜索。
令我困惑的是,我在以下语句 Query query = fullTextSession.createFullTextQuery(luceneQuery, ProductA.class); 在方法 searchProducts() 中。为什么 Hibernate Search 还搜索 ProductB 和 ProductC 实体?
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/