Hibernate搜索分页奇怪的行为
嗨,我们正在使用hibernate搜索和elasticsearch 索引工作如预期,但是我们在分页结果时看到奇怪的行为Hibernate搜索分页奇怪的行为,hibernate,
elasticsearch,hibernate-search,Hibernate,
elasticsearch,Hibernate Search,嗨,我们正在使用hibernate搜索和elasticsearch 索引工作如预期,但是我们在分页结果时看到奇怪的行为 org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(query, Person.class).setFirstResult(0).setMaxResults(10); return hibQuery.list(); 如果省略setFirstResult(0).setM
org.hibernate.Query hibQuery =
fullTextSession.createFullTextQuery(query,
Person.class).setFirstResult(0).setMaxResults(10);
return hibQuery.list();
如果省略setFirstResult(0).setMaxResults(10),我们将得到700个结果,但设置了两个参数后,我们将得到0个结果
进一步的研究表明,问题在于hibernate搜索中QueryLoader中的这段代码
objectInitializer.initializeObjects(
entityInfos,
idToObjectMap,
new ObjectInitializationContext( criteria, entityType, extendedIntegrator, timeoutManager, session )
);
ArrayList<Object> result = new ArrayList<>( idToObjectMap.size() );
for ( Object o : idToObjectMap.values() ) {
if ( o != ObjectInitializer.ENTITY_NOT_YET_INITIALIZED ) {
result.add( o );
}
}
return result;
对于所有idToObjectMap条目返回false
进一步的研究表明,hibernate构建了查询,sql看起来是正确的,但是在QueryParanters中,object callable被设置为false,并且查询永远不会执行
相关LIB
compile "org.hibernate:hibernate-core:5.9.2.Final"
compile "org.hibernate:hibernate-search-orm:5.9.2.Final"
compile "org.hibernate:hibernate-search-elasticsearch:5.9.2.Final"
如果您能帮助解释为什么会发生这种情况,以及如何正确实现分页,我们将不胜感激。当实体出现在索引中时,通常会出现这种情况,但数据库中不再出现这种情况。在您的例子中,前10个结果似乎在索引中,但不在数据库中 这种行为的原因是Elasticsearch是“接近实时的”:在我们对索引进行更改后,更改将需要一段时间(通常几秒钟)才能在搜索结果中显示出来。因此,如果您只是在几毫秒之前删除了实体,索引状态可能会“滞后”于数据库状态 如果确定数据库中仍然存在实体,则ID映射或选择的特定查询配置可能存在问题。如果未使用默认值,请向我们显示
Person
类的代码,并提供您为属性hibernate.search.query.object\u lookup\u方法
和hibernate.search.query.database\u retrieval\u方法
设置的值
试验中的溶液
如果测试时出现问题,可以将hibernate.search.default.elasticsearch.refresh\u-after\u-write
设置为true
但不应在生产中设置此项,因为这将大大降低索引的性能
生产中的溶液
如果这是生产中的一个问题,并且您需要有效地解决它,那么它将更加困难。我能想到的唯一解决方案是从按索引分页改为按键分页。但是,您将失去直接转到页面的功能,并且无法按任何方式对结果进行排序
您需要在结果中找到一个严格单调的键,即保证每个结果唯一的字段,并且在转到下一个结果时总是增加(或总是减少)。如果您按id排序,id将是一个很好的候选者。如果创建日期足够精确,并且您按此创建日期排序,那么创建日期也可以工作
您将使用此键忽略前面的页面:客户端不会将页码发送到服务器,它将发送“严格单调”键的最后一个值,您只需向查询中添加一个类似这样的谓词:queryBuilder.range().onField(“myKey”).over().createQuery()
然后,不直接返回查询结果,而是多次执行查询,将结果累积到列表中,直到达到适当的页面大小(或直到getResultSize
返回0)
编辑:另一种解决方案,可能更简单,但这只会降低出现此问题的可能性,而不会完全消除它
通过将所有索引设置为比默认值更短的值(1s
),可以确保Elasticsearch更频繁地刷新其索引。注意,这可能会对Elasticsearch集群的性能产生非常坏的影响,具体取决于您写入集群的频率
要将该设置应用于所有索引,最简单的解决方案是在Hibernate Search创建索引之前创建。您好,谢谢您的评论。对象存在于数据库中,我们使用所有默认设置。我发现了正在发生的事情,但不知道为什么。我将把这些信息添加到我的原始问题中。嗨,我发现这些对象已经不在数据库中了。我们不会删除应用程序中的对象,因此我假设它们就在那里。但是,我们在dev中有一个单独的作业,用于清理数据库,我必须在创建索引后运行它。问题是,外部作业实际上使用原始sql从数据库中删除了一些条目,这导致了问题。再次感谢@yrodiere为我指明了正确的方向,也感谢其他有用的提示。
compile "org.hibernate:hibernate-core:5.9.2.Final"
compile "org.hibernate:hibernate-search-orm:5.9.2.Final"
compile "org.hibernate:hibernate-search-elasticsearch:5.9.2.Final"