Java 为什么Hibernate搜索很慢?即使记录很少
我有一个使用JSF2、Spring、JPA2和HibernateSearch4.5.0的项目。这个项目非常简单,但Hibernate搜索给我带来了一些麻烦 我使用Hibernate搜索的唯一部分是为Oracle视图编制索引。这个视图,如果我从我的_视图运行一个简单的Java 为什么Hibernate搜索很慢?即使记录很少,java,hibernate,jpa,hibernate-search,Java,Hibernate,Jpa,Hibernate Search,我有一个使用JSF2、Spring、JPA2和HibernateSearch4.5.0的项目。这个项目非常简单,但Hibernate搜索给我带来了一些麻烦 我使用Hibernate搜索的唯一部分是为Oracle视图编制索引。这个视图,如果我从我的_视图运行一个简单的选择count(*),会给我5756条记录,这并不多 我做的第一件事是使用JPA/Hibernate搜索进行实体映射: @Entity @Indexed @Table(name = "my_view") public class Pe
选择count(*),会给我5756条记录,这并不多
我做的第一件事是使用JPA/Hibernate搜索进行实体映射:
@Entity
@Indexed
@Table(name = "my_view")
public class Person implements Serializable {
private static final long serialVersionUID = 244555315052436669L;
@Id
@Column(name = "id", insertable = false, updatable = false)
private Long id;
@Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
@Column(name = "name", insertable = false, updatable = false)
private String name;
@Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
@Column(name = "email", insertable = false, updatable = false)
private String email;
@Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
@Column(name = "user", insertable = false, updatable = false)
private String user;
@Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
@Column(name = "phone", insertable = false, updatable = false)
private String phone;
//Getters and Setters ommited
}
映射实体后,我构建了一个cronJob来索引该实体。看看我用来索引实体的方法
public void index() throws DAOException {
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(this.entityManager);
try {
fullTextEntityManager.createIndexer(Person.class)
.purgeAllOnStart(Boolean.TRUE)
.optimizeOnFinish(Boolean.TRUE)
.startAndWait();
}
catch (InterruptedException e) {
logger.error("Error creating index", e);
throw new DAOException(e);
}
}
而且,在索引实体之后,我可以用一个关键字搜索多个列问题是当我尝试在没有任何关键字的情况下搜索时我的应用程序必须返回所有记录。但是我想,使用Hibernate搜索,这个搜索会非常快。我错了
搜索需要40多秒才能返回!以下是我如何在没有术语的情况下进行搜索:
FullTextEntityManager fullTextEm = Search.getFullTextEntityManager(this.entityManager);
QueryBuilder qb = fullTextEm.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get();
FullTextQuery fullTextQuery = fullTextEm.createFullTextQuery(qb.all().createQuery());
Sort sortField = new Sort(new SortField("name", SortField.STRING));
fullTextQuery.setSort(sortField);
return fullTextQuery.getResultList();
查询执行可能非常快(因为不使用关键字进行搜索非常有效),但执行的下一步是将所有结果从数据库加载到内存中,并且从数据库加载5000多个元素永远不会很快,除非您查看实体和查询的缓存
如果您需要加载所有内容,那么这不是全文查询,而是由标准关系查询更好地执行。
无论查询类型是什么——除非您使用投影——您可能还希望调查您的模型导致的加载策略。通常,通过调整某些关系的获取策略和/或启用二级缓存,您可以获得显著的提升。问题通过解决!多亏了,还有
我不得不修改一些代码。我做的第一件事是改变查询数据的方式,以使用预测
FullTextEntityManager fullTextEm = Search.getFullTextEntityManager(this.entityManager);
QueryBuilder qb = fullTextEm.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get();
FullTextQuery fullTextQuery = fullTextEm.createFullTextQuery(qb.all().createQuery());
// I added this line to use projections
fullTextQuery.setProjection("id", "name", "email", "user", "phone");
Sort sortField = new Sort(new SortField("name", SortField.STRING));
fullTextQuery.setSort(sortField);
return fullTextQuery.getResultList();
但是,当我使用投影时,查询不会返回特定对象的列表(在我的例子中:Person.class
),而是返回object[].class
的列表。因此,我编写了一个方法将List
转换为List
。代码如下:
private List<Person> toList(List<Object[]> objPeople) {
List<Person> lstPeople = new LinkedList<Person>();
Person Person = null;
for(Object[] objPerson : objPeople) {
Person p = new Person();
p.setId(Long.parseLong(objPerson[0].toString()));
p.setName(String.valueOf(objPerson[1] == null ? "" : objPerson[1]));
p.setEmail(String.valueOf(objPerson[2] == null ? "" : objPerson[2]));
p.setUser(String.valueOf(objPerson[3] == null ? "" : objPerson[3]));
p.setPhone(String.valueOf(objPerson[4] == null ? "" : objPerson[4]));
lstPeople.add(Person);
}
return lstPeople;
}
成功了要开始,请打开Hibernate的SQL查询日志记录,并手动运行生成的查询,查看是在Hibernate中还是在数据库中减速。如果它在数据库中,请确保查询看起来正常,然后使用数据库探查器。我不明白。我认为在索引查询之后(无论在数据库中运行查询需要多少时间),hibernate search只使用索引,不在数据库中再次运行查询。我错了吗?Hibernate Search将对Lucene索引运行查询,以获取匹配记录的ID,然后使用这些ID查询数据库以检索完整数据。要仅从索引检索数据,您需要使用投影。感谢@RandomMooCow提供的信息。你知道我在哪里可以找到关于在我的项目中使用的投影的好资源吗?是的,应该能够提供帮助。你可能仍然需要分页,因此你可能需要查看:。通常盲目的getResultList()
是个坏主意。我来看看!谢谢你的提示。
@Entity
@Indexed
@Table(name = "my_view")
public class Person implements Serializable {
private static final long serialVersionUID = 244555315052436669L;
@Id
@Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
@Column(name = "id", insertable = false, updatable = false)
private Long id;
@Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
@Column(name = "name", insertable = false, updatable = false)
private String name;
@Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
@Column(name = "email", insertable = false, updatable = false)
private String email;
@Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
@Column(name = "user", insertable = false, updatable = false)
private String user;
@Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
@Column(name = "phone", insertable = false, updatable = false)
private String phone;
//Getters and Setters ommited
}