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

阵列

我在使用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),以及一组具有该个人资料收藏夹的用户(favouritesMap)。我已经包括了FavouritesMap实体类和关联的id类,AdminMap遵循相同的结构。Profile实体没有直接索引,但是它的扩展类型是。

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

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)时,休眠搜索会看到@ContainedIn字段“ profile”,查找该配置文件项的索引,然后仅添加新字段(favouritesMap.id.userId )到索引中的该配置文件项目。

但是,似乎正在发生的情况是,休眠搜索正在初始化配置文件实体中的所有集合(adminMap,favouritesMap和childrenProfiles)。在我的某些情况下,这导致获取1000个关联实体,从而导致巨大的性能问题。方法setAsFavourite返回一个FavouritesMap对象,并且配置文件字段的集合都已完全初始化,这证明了这一点。如果我删除了休眠搜索注释,则该对象将正确返回未初始化的惰性集合,表明这是休眠搜索问题。

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

谢谢

桑内

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

即使只更改了一个字段,Lucene文档也需要完全重写以进行任何更新。

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

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

Hibernate Search包含用于“脏检查”的策略,这些策略超出了Hibernate ORM所应用的策略:我们尽力弄清楚是否不能跳过索引更新,但是如果需要进行写操作,则实际上确实需要将整个图读取到产生一个新的文件。

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

尤其重要的是,请确保使用以下选项明确界定实际需要建立索引的对象图的界限:

  • @IndexedEmbeddedincludePaths
  • @IndexedEmbedded深度

默认值可能是索引比实际需要更多的分支。

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章