gpt4 book ai didi

java - Hibernate Search 5.5.2 - 具有许多关联的对象的索引更新性能较差

转载 作者:行者123 更新时间:2023-11-30 07:20:39 41 4
gpt4 key购买 nike

我在使用 Hibernate Search 时遇到了严重的性能问题。似乎当我保存/更新/删除通过 @IndexedEmbedded 或 @ContainedIn 引用的实体时 - 父索引实体会经历作为索引图一部分的所有惰性集合的完整初始化。在某些情况下,这是初始化并从数据库中获取数千个关联对象。我不确定这是否是预期的行为,但我想只有正在更新/添加的字段需要在索引中更新/添加,并且不明白为什么我的惰性集合需要初始化。

下面是简化的代码,显示了我如何设置实体和搜索图:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Profile {

@Id
public int id;
@Field
public String name;

@IndexedEmbedded(includePaths = "name")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(referencedColumnName = "id")
public Profile parentProfile;

@ContainedIn
@OneToMany(mappedBy = "parentProfile")
public Set<Profile> childrenProfiles = new HashSet<Profile>();

@IndexedEmbedded(includePaths = { "id.userId" })
@OneToMany(mappedBy = "profile")
public Set<AdminMap> adminMap = new HashSet<AdminMap>();

@IndexedEmbedded(includePaths = { "id.userId" })
@OneToMany(mappedBy = "profile")
public Set<FavouritesMap> favouritesMap = new HashSet<FavouritesMap>();

}

@Indexed
@Entity
public class BusinessProfile extends Profile {...}

@Indexed
@Entity
public class UserProfile extends Profile {...}

@Entity
public class FavouritesMap {

@EmbeddedId
@IndexedEmbedded
public FavouritesMapId id;

@ContainedIn
@ManyToOne
@JoinColumn(insertable = false, updatable = false)
public Profile profile;

@ManyToOne
@JoinColumn(insertable = false, updatable = false)
public User user;

}

@Embeddable
public class FavouritesMapId {

@Field
public int userId;
public int profileId;
}

因此,我们有一个 Profile 实体,它可以有 1 个父级和多个子级。配置文件还具有一组作为配置文件管理员的用户 (adminMap),以及一组 Collection 该配置文件的用户 (favouritesMap)。我已经包含了 FavouritesMap 实体类和关联的 id 类,AdminMap 遵循相同的结构。 Profile 实体不是直接索引的,但它的扩展类型是。

这是用户执行“Collection ”个人资料操作时的代码:

public FavouritesMap setAsFavourite(int userId, int profileId) {
FavouritesMap fav = new FavouritesMap(new FavouritesMapId(userId, profileId));

Profile profile = (Profile)entityManager.findById(Profile.class, profileId);
fav.setProfile(profile);

entityManager.save(fav);

return fav;
}

我期望发生的是,当我们调用entityManager.save(fav)时,hibernate搜索会看到@ContainedIn字段“profile”,查找该配置文件项的索引,然后添加新字段(favouritesMap. id.userId) 到索引中的该配置文件项目。

但是,似乎正在发生的情况是,hibernate 搜索正在初始化配置文件实体中的所有集合(adminMap、favouritesMap 和childrenProfiles)。在我的某些情况下,这会导致获取数千个关联实体,从而导致巨大的性能问题。这可以通过 setAsFavourite 方法返回一个 FavouritesMap 对象来证明,其中配置文件字段的集合已全部初始化。如果我删除 hibernate 搜索注释,则该对象将正确返回未初始化的惰性集合,表明这是 hibernate 搜索问题。

所以我的问题是,在通过 @ContainedIn 引用添加项目时, hibernate 搜索初始化所有这些惰性集合并重新索引所有字段的正确行为是否正确?如果是这样,...为什么?当然,它只需要添加一个新字段,而不是重新验证该实体的整个索引。如果没有,我的设置是否存在任何明显的错误,或者我如何最好地调试此问题?

谢谢

最佳答案

您的观察是正确的,简短的答案是:这是必需的。

任何更新都需要完全重写 Lucene 文档,即使只有一个字段发生变化。

请记住,Lucene 不是关系数据库:您不能只更新一个“列”,而是需要您再次编写文档,本质上是删除前一个文档并重新插入一个新副本。

无法读取现有文档,因为索引通常不是双向转换,这需要将所有字段标记为“已存储” - 从性能角度来看,这也是不可取的。即使您将所有字段标记为已存储,由于操作的重新排序,读取索引文档仍然不安全,并且可能会导致最终索引状态不一致。

Hibernate Search 包含“脏检查”策略,这些策略超出了 Hibernate ORM 所应用的策略:我们努力确定是否无法跳过索引更新,但如果需要进行写入,则确实需要完整的图被阅读以生成新的文档。

除了尝试限制索引的递归字段的深度之外,一种常见的技术是启用二级缓存并确保在频繁读取的关联上广泛启用它。

尤其重要的是,请确保使用以下选项清楚地界定您实际需要索引的对象图:

  • @IndexedEmbedded(includePaths)
  • @IndexedEmbedded(深度)

默认情况下索引的分支可能多于您实际需要的分支。

将来,我们计划能够通过使用显式索引时间连接将文档“分解”为两部分,但即使我们这样做,您也需要牢记这一限制,因为 Lucene 不会这样做不支持关系数据库可以提供的同类联接:我们可能只能在一个特定点拆分文档(只能考虑一个联接)。

关于java - Hibernate Search 5.5.2 - 具有许多关联的对象的索引更新性能较差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37627637/

41 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com