【问题标题】:Hibernate Search not returning results on newly created entities休眠搜索不返回新创建实体的结果
【发布时间】:2019-07-30 00:03:06
【问题描述】:

我在多租户 Hibernate 应用程序中使用 Hibernate Search。根据this 链接,我希望这可以开箱即用,但搜索结果似乎没有返回新创建的实体。

这是我的映射:

@Entity
@Indexed
public class ItemEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Field
    private String name;

    @Field
    private String description;

    @OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval = true)
    @OrderBy("versionNo DESC, lastSaveDate DESC")
    @IndexedEmbedded
    private List<ItemVersionEntity> versions;

    ...
}
@Entity
public class ItemVersionEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Field
    private String description;

    @OneToMany(mappedBy = "version", cascade = CascadeType.ALL, orphanRemoval = true)
    @Fetch(FetchMode.SUBSELECT)
    @IndexedEmbedded
    private List<ItemEdgeEntity> edges;

    @OneToMany(mappedBy = "version", cascade = CascadeType.ALL, orphanRemoval = true)
    @Fetch(FetchMode.SUBSELECT)
    @IndexedEmbedded
    private List<ItemNodeEntity> nodes;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "item_id")
    @ContainedIn
    private ItemEntity item;
}
@Entity
public class ItemEdgeEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Field
    private String text;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "version_id")
    @ContainedIn
    private ItemVersionEntity version;
}
@Entity
public class ItemNodeEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Field
    private String text;

    @Field
    private String description;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "version_id")
    @ContainedIn
    private ItemVersionEntity version;
}

添加了一个ItemNodeEntityfoobar之后,我用this工具查看它出现在索引中(虽然我不太了解索引的结构,也不确定不同的Segment有问题):
Marple image
Luke image

这是一些返回0结果的查询代码:

SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
Session session = sessionFactory.withOptions().tenantIdentifier(tenantIdResolver.resolveCurrentTenantIdentifier()).openSession();
FullTextSession fullTextEM = Search.getFullTextSession(session);

QueryBuilder itemQB = fullTextEM.getSearchFactory().buildQueryBuilder().forEntity(ItemEntity.class).get();

Query mq = itemQB
                .keyword()
                .onField("versions.nodes.text")
                .matching("foobar")
                .createQuery();

FullTextQuery ft = fullTextEM.createFullTextQuery(mq, ItemEntity.class);
List<Object> result = ft.getResultList();

请注意,如果我重新索引整个数据库,则上述搜索有效:

FullTextSession fullTextEntityManager = Search.getFullTextSession(session);
fullTextEntityManager.createIndexer().startAndWait();

休眠:5.2.13 休眠搜索:5.9.3

编辑:

似乎在保存ItemVersionEntity 后,__HSearch_TenantId 字段已从 Lucene 文档中删除: Luke document image

这是实现多租户的方式(基本上遵循this 指南):

@Configuration
public class HibernateConfig {

    @Autowired
    private JpaProperties jpaProperties;

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        return new HibernateJpaVendorAdapter();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
                                                                       MultiTenantConnectionProvider multiTenantConnectionProviderImpl,
                                                                       CurrentTenantIdentifierResolver currentTenantIdentifierResolverImpl) {

        Map<String, Object> properties = new HashMap<>();
        properties.putAll(jpaProperties.getHibernateProperties(new HibernateSettings()));

        properties.put(Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
        properties.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProviderImpl);
        properties.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolverImpl);

        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource);
        em.setPackagesToScan(...);
        em.setJpaVendorAdapter(jpaVendorAdapter());
        em.setJpaPropertyMap(properties);

        return em;
    }
}

【问题讨论】:

    标签: hibernate hibernate-search


    【解决方案1】:

    正如我在另一个答案的 cmets 中所讨论的,这是一个仅在非常特定的情况下使用多租户时才会出现的错误(显然,@IndexedEmbedded 的 2 个或更多级别):https://hibernate.atlassian.net/browse/HSEARCH-3647

    要解决此错误,您可以做的最好的事情是在合并后明确地重新索引:

    Search.getFullTextSession(s).index(updatedVersion.getItem());
    

    如果您实际上无法提前知道哪些实体需要重新索引,那么您可能会使用一种 hack……但它确实是一种 hack:请务必正确测试它。这个想法是让 Hibernate Search 执行一个不会改变任何东西的操作,但会产生正确初始化一些内部结构的副作用。 开始交易后,只需使用您绝对确定不匹配任何实体的实体 ID 触发您绝对确定不会产生任何影响的清除操作:

    Search.getFullTextSession(s).purge(ItemEntity.class, -1);
    

    然后该实体类型的内部结构将被正确初始化,@ContainedIn 处理将在事务的其余部分正常工作。 如果您有其他索引类型,则必须对可能受交易影响的每种类型执行相同的操作。

    注意清除操作仍然会被执行,只是它不会有任何效果,因为 ID 不匹配任何东西。

    【讨论】:

      【解决方案2】:

      您的映射似乎缺少从 ItemVersionEntityItemEntity 的关联。您需要此关联以及 @ContainedIn 注释,以便 Hibernate Search 能够检索相关的 ItemEntity 实例并在 ItemVersionEntity(或嵌入式节点)更改时对其重新编制索引。

      基本上,如果您希望自动重新索引正常工作,只要实体 A 在与类型 B 的关联上带有 @IndexedEmbedded 注释,您就需要实体 B 将该关联的反面声明为类型 A,并且在该反向关联上添加 @ContainedIn 注释。

      【讨论】:

      • 对不起,我的错误 - @ContainedIn 确实存在于 ItemVersionEntity - 我刚刚在删除不相关的属性时错误地删除了它。我已经更新了问题。
      • 添加节点时是否还确保更新关联的双方?这是另一个潜在的陷阱。
      • 嗯,关联是双向更新的,但是在您提到它之后,它可能与使用 session.merge(version) 保存 ItemVersionEntity 的事实有关 - 其​​中 nodes list 是现有(带 ID)和新(不带 ID)对象的混合体——不过,它们都具有 version 后向引用集。奇怪的是 foobar 术语看起来已经在索引中(安装了 Luke 以及我在问题中提到的其他应用程序,它也出现在 Luke 中)
      • 我刚刚注意到您正在使用多租户。索引中的__HSearch_TenantId 字段是否具有您期望的值?
      • 在 Luke 中检查,我可以看到,一旦我保存了 ItemVersionEntity,Lucene 文档上就根本没有 __HSearch_TenantId 字段了。因此,以某种方式保存会删除 __HSearch_TenantId 字段。我会用设置多租户属性的方式更新问题,问题一定出在哪里?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-19
      • 1970-01-01
      • 2021-11-12
      • 1970-01-01
      相关资源
      最近更新 更多