【问题标题】:Spring Boot 2 with Hibernate Search, indexes are not created on save带有 Hibernate Search 的 Spring Boot 2,保存时不创建索引
【发布时间】:2020-03-04 23:28:43
【问题描述】:

我有一个如下定义的实体。如果我使用 save() Hibernate 不会为新创建的实体创建新索引。更新/修改现有实体效果很好,符合预期。

我正在使用带有 spring boot 2 的 kotling。

@Entity(name = "shipment")
@Indexed
data class Shipment(
        @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = -1,
        @JoinColumn(name = "user") @ManyToOne() var user: User?,
        @IndexedEmbedded
        @JoinColumn(name = "sender") @ManyToOne(cascade = [CascadeType.ALL]) val sender: Contact,
        @IndexedEmbedded
        @JoinColumn(name = "sender_information") @ManyToOne(cascade = [CascadeType.ALL]) val senderInformation: ShipmentInformation,
) {}

保存功能,我正在使用相同的功能来更新我的实体,如果索引存在,则会更新索引。

    @Transactional
    fun save(user: User, shipment: Shipment): Shipment {
        shipment.user = user;
        return this.shipmentRepository.save(shipment)
    }

application.properties

spring.jpa.properties.hibernate.search.default.directory_provider=filesystem
spring.jpa.properties.hibernate.search.default.indexBase=./lucene/
spring.jpa.open-in-view=false

如果我重新启动服务器,手动索引也可以工作。

    @Transactional
    override fun onApplicationEvent(event: ApplicationReadyEvent) {
        val fullTextEntityManager: FullTextEntityManager = Search.getFullTextEntityManager(entityManager)
        fullTextEntityManager.createIndexer().purgeAllOnStart(true)
        fullTextEntityManager.createIndexer().optimizeAfterPurge(true)
        fullTextEntityManager.createIndexer().batchSizeToLoadObjects(15)
        fullTextEntityManager.createIndexer().cacheMode(CacheMode.IGNORE)
        fullTextEntityManager.createIndexer().threadsToLoadObjects(2)
        fullTextEntityManager.createIndexer().typesToIndexInParallel(2)
        fullTextEntityManager.createIndexer().startAndWait()
        return
    }

我试图强制使用 JPA 事务管理器,但它对我没有帮助。

    @Bean(name = arrayOf("transactionManager"))
    @Primary
    fun transactionManager(@Autowired entityManagerFactory: EntityManagerFactory): org.springframework.orm.jpa.JpaTransactionManager {
        return JpaTransactionManager(entityManagerFactory)
    }

更新

我想我找到了为什么我没有得到新插入实体的结果。

我的搜索查询在声明的“pid”字段上有一个条件:

        @Field(index = Index.YES, analyze = Analyze.NO, store = Store.NO)
        @SortableField
        @Column(name = "id", updatable = false, insertable = false)
        @JsonIgnore
        @NumericField val pid: Long,

和查询:

query.must(queryBuilder.keyword().onField("customer.pid").matching(user.customer.id.toString()).createQuery())

pid 未存储,因此新插入的值不可见。这可能是原因吗?

顺便说一句:如何按嵌套索引文档 ID 查询/搜索?在我的例子中,customer.id 是 DocumentId。我尝试更改如下查询但没有得到任何结果,我应该创建一个新字段来查询吗?

query.must(queryBuilder.keyword().onField("customer.id").matching(user.customer.id.toString()).createQuery())

更新 2

我找到了一个解决方案,现在也得到了新插入的数据。 “pid”字段的定义出错,我已将我的字段定义如下,它按预期工作。

        @Fields(
                Field(name = "pid", index = Index.YES, analyze = Analyze.YES, store = Store.NO)
        )
        @SortableField(forField = "pid")
        @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long?,

我们能否以一种简单的方式按 id 进行搜索和排序,或者这是最佳做法?我知道我们应该使用本机 JPA 函数来通过 id 获取结果,但在我的情况下,我需要通过嵌入式 id 进行搜索以限制搜索结果。 (取决于用户的角色)所以这不是我的选择。

而且我不明白为什么手动索引有效......

【问题讨论】:

    标签: spring-boot jpa kotlin hibernate-search


    【解决方案1】:

    顺便说一句:如何按嵌套索引文档 ID 查询/搜索?在我的例子中,customer.id 是 DocumentId。我尝试更改如下查询但没有得到任何结果,我应该创建一个新字段来查询吗?

    如果您只想执行完全匹配,通常您不需要创建单独的字段。

    我们可以用简单的方式搜索和排序吗

    搜索,是的,至少在 Hibernate Search 5 中。

    排序,不:您需要一个专用字段。

    还是最好的做法?

    如果您需要比 ID 完全匹配更复杂的内容,最佳做法是在您的 @DocumentId 旁边声明一个字段。

    我知道我们应该使用原生 JPA 函数来通过 id 获取结果

    我不确定我理解您所说的“本机 JPA 函数”是什么意思。

    但在我的情况下,我需要通过嵌入的 id 进行搜索以限制搜索结果。 (取决于用户的角色)

    是的,这应该可以。也就是说,如果正确填充了 id,它应该可以工作。

    而且我不明白为什么手动索引有效......

    我也没有,但我想解释在于““pid”字段定义中的错误”。也许在某些情况下没有正确填充 ID,导致实体被 Hibernate Search 视为已删除?

    如果你需要我给你一个明确的答案,最好的方法是创建一个复制器。您可以将其用作模板:https://github.com/hibernate/hibernate-test-case-templates/tree/master/search

    【讨论】:

    • 非常感谢您非常有帮助的回答。 :) 我有一个关于完全匹配的小问题:queryBuilder.keyword().onField("customer.id").matching(user.customer.id) 如果我在 @Id 字段上使用它,我不明白任何结果。我是否为完全匹配构建了错误的查询?
    • 我在您的模型中没有看到任何“客户”字段,所以是的,这似乎是错误的。仔细检查您的字段名称?
    【解决方案2】:

    这看起来很奇怪:

            @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = -1,
    

    我希望有一个可以为空的 long,初始化为 null(或 Kotlin 等价物)。

    我不确定这是否是问题所在,但我想可能是这样,因为非空 ID 通常只期望来自已持久化的实体。

    除此之外,我认为您走在正确的轨道上:如果海量索引有效但自动索引无效,则可能与您的更改未在数据库事务中执行有关。

    【讨论】:

    • 我将其更改为`@Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long?` 所以 id 为空,但我没有帮助。如果我调用搜索功能保存后,我仍然会得到启动时索引的结果。服务器重启后,我得到了实体,包括保存的新实体。
    • 您的日志中没有任何内容?您能否将记录器“org.hibernate.search”的级别设置为 TRACE,插入一些实体并将生成的日志发布到 pastebin.com
    • gist.github.com/nodify-at/4cdefa11c10527b81a4249ee7448bc0a 谢谢,索引看起来不错,但是为什么不重新启动服务器就不能得到这个实体?
    • 我更新了包括搜索日志在内的要点,预计为 11,但它返回 10
    • 你能检查我更新的问题吗?我想我找到了为什么我没有得到新插入的行。
    猜你喜欢
    • 2019-06-14
    • 1970-01-01
    • 2020-05-17
    • 2018-07-25
    • 1970-01-01
    • 2019-01-09
    • 2016-10-29
    • 2019-11-28
    • 1970-01-01
    相关资源
    最近更新 更多