【问题标题】:How to achieve full text search for nested deep nested objects using apache lucene? in a Spring boot project如何使用apache lucene实现对嵌套深层嵌套对象的全文搜索?在 Spring Boot 项目中
【发布时间】:2019-10-15 09:35:45
【问题描述】:

我是 apache lucene 或任何其他 fts 引擎的新手,对此深感抱歉 我已经成功地实现了 apache lucene 和 hibernate search orm 但是当涉及到嵌套关系时,只要我理解并尝试过,它只工作一层。所以我可以实现搜索多于两层的嵌套对象,如下所示

应在此模型上执行 FTS,特别是字段 User 和 UserSubCategory

 @Entity
@org.hibernate.search.annotations.Indexed
class SubCategoryUserManyToMany(
        @ManyToOne(fetch = FetchType.LAZY, optional = false)
        @JoinColumn(name = "user_id", nullable = false)
        @IndexedEmbedded
        var user: User? = null,
        @ManyToOne(fetch = FetchType.LAZY, optional = false)
        @JoinColumn(name = "category_id", nullable = false)
        @IndexedEmbedded
        var subCategory: UserSubCategory? = null,
        @Field(index = Index.NO)
        var jobType: JobType?= JobType.HOURLY,
        @Field(index = Index.NO)
        var price: Long = 0
): BaseModel()

我正在对用户模型的两个字段进行 fts,名字和姓氏。它工作得很好

@Entity
@Table(name = "users")
class User() : BaseModel() {

    @Column(unique = true, name = "email")
    @NotBlank
    @Email
    var email: String? = null

    @Column(name = "firstname")
    @Size(max = 100)
    @Field
    var firstname: String? = null

    @Column(name = "lastname")
    @Size(max = 100)
    @Field
    var lastname: String? = null

    @Column(name = "midname")
    @Size(max = 100)
    var midname: String? = null

    @Column(name = "password")
    @Size(max = 100)
    var password: String? = null

    @NotBlank
    @Column(name = "phone", unique = true)
    @Size(max = 100)
    var phone: String? = null


    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "user_roles",
            joinColumns = [JoinColumn(name = "user_id", referencedColumnName = "id")],
            inverseJoinColumns = [JoinColumn(name = "role_id", referencedColumnName = "id")])
    var roles: MutableList<Role> = mutableListOf()



    //TODO CATEGORY RELATIONSHIPS
    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    @ContainedIn
    var subCategoryUserManyToMany: MutableList<SubCategoryUserManyToMany> = mutableListOf()


    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_images_many_to_many",
            joinColumns = [JoinColumn(name = "user_id", referencedColumnName = "id")],
            inverseJoinColumns = [JoinColumn(name = "attachment_id", referencedColumnName = "id")])
    var images: MutableList<Attachment> = mutableListOf()



    constructor(id: Long) : this() {
        this.id = id
    }
}

然而,当涉及到 UserSubCategory 时,

   @Entity
class UserSubCategory (
        @ManyToOne(fetch = FetchType.LAZY, optional = false)
        @JoinColumn(name = "category_id", nullable = false)
        var category: UserCategory? = null,

        @OneToOne(fetch = FetchType.LAZY, optional = false)
        @JoinColumn(name = "title_id", nullable = false)
        var title: TextValueShort? = null,

        @OneToMany(mappedBy = "subCategory", fetch = FetchType.LAZY)
        @ContainedIn
        var subCategoryUserManyToMany: MutableList<SubCategoryUserManyToMany> = mutableListOf(),

        @ManyToMany(fetch = FetchType.LAZY)
        @JoinTable(name = "master_subcategory_job_descriptions",
                joinColumns = [JoinColumn(name = "sub_cat_id", referencedColumnName = "id")],
                inverseJoinColumns = [JoinColumn(name = "text_id", referencedColumnName = "id")])
        var whatShouldBeDoneList: MutableList<TextValueMedium> = mutableListOf()
) : BaseModel(){
        constructor(id: Long): this(){
                this.id = id
        }
}

如您所见,我有 title 字段,这是应该进行 FTS 的另一种关系 型号

 @Entity
@Table(name = "txt_value_short")
class TextValueShort {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    var id: Long? = null

    @Size(max=150)
    var ru : String? = null
    @Size(max=150)
    var en : String? = null
    @Size(max=150)
    var uz : String? = null

}

这是我的搜索功能

 override fun masterSearch(searchTerm: String, fields: Array<String>,  pageNo: Int,  resultsPerPage: Int): Page<SubCategoryUserManyToMany> {
        val fullTextEntityManager = Search.getFullTextEntityManager(entityManager)

        val qb = fullTextEntityManager.searchFactory.buildQueryBuilder().forEntity(SubCategoryUserManyToMany::class.java).get()

        val luceneQuery: org.apache.lucene.search.Query = qb
                .bool()
                .should(qb.keyword().onFields("user.firstname", "user.lastname", "subCategory.title.en").matching(searchTerm).createQuery())
                .should(qb.keyword().wildcard().onFields("user.firstname", "user.lastname", "subCategory.title.en").matching("*$searchTerm*").createQuery())
                .createQuery()

        val jpaQuery = fullTextEntityManager.createFullTextQuery(luceneQuery, SubCategoryUserManyToMany::class.java)
        jpaQuery.maxResults = resultsPerPage
        jpaQuery.firstResult = (pageNo) * resultsPerPage

        var result = listOf<SubCategoryUserManyToMany>()

        try {
            result = jpaQuery.resultList as List<SubCategoryUserManyToMany>
        }catch (ex: Exception){}

        val page = PageRequest(pageNo, resultsPerPage )

        return PageImpl(result, page, result.size.toLong())
    }

如你所见,我有一个抛出异常的“subCategory.title.en”

【问题讨论】:

    标签: hibernate spring-boot lucene hibernate-search


    【解决方案1】:

    UseSubCategory.title 未编入索引。 要对其进行索引,请在此属性上添加 @IndexedEmbedded,就像为 SubCategoryUserManyToMany.title 所做的一样,并在 TextValueShort 的各种属性上添加 @Field 注释(enru,...)。

    但有一个警告:由于TextValueShort 没有对UseSubCategory 的向后引用,因此您不能使用@ContainedIn。这意味着对TextValueShort 的更改不会触发UseSubCategorySubCategoryUserManyToMany 的重新索引。

    这个问题有三种解决方案:

    1. 如果您可以更改数据库架构,这可能是最好的解决方案:将TextValueShort 转换为@Embeddable 而不是@Entity。在这种情况下,Hibernate Search 可以很好地处理重新索引。
    2. 可能不可能:将UserSubCategory userSubCategory 属性添加到TextValueShort 并使用@OneToOne(mappedBy = "title)@ContainedIn 对其进行注释。
    3. 每次更改标题时手动处理重新索引。见https://docs.jboss.org/hibernate/search/5.11/reference/en-US/html_single/#_adding_instances_to_the_index

    【讨论】:

    • 哇,我错过了!每次标题更新时我应该索引哪个类?是 SubCategoryUserManyToMany 吗?我想我会去手动索引谢谢@yrodiere
    • 您应该重新索引嵌入标题的索引实体,所以是的,SubCategoryUserManyToMany
    【解决方案2】:

    我在标签 hibernate-search 下搜索时找到了解决问题的方法,有一个类似的情况,应该索引三层嵌套关系,但我的只是 2 层,感谢回答的人关于休眠搜索的每一个问题 链接:yrodiere's answer

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-01
      • 2018-01-22
      • 1970-01-01
      • 1970-01-01
      • 2018-01-25
      • 1970-01-01
      相关资源
      最近更新 更多