如何使用apache lucene实现嵌套深层嵌套对象的全文搜索?在 Spring 引导项目中

How to achieve full text search for nested deep nested objects using apache lucene? in a Spring boot project

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

FTS should be performed on this model, specifically fields User and 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()

I am doing fts on two fields of User model, firstname and lastname. It is working just fine

@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
    }
}

However when it comes to UserSubCategory which is

   @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
        }
}

As you can see I have title field which is another relationship on which FTS should be done Model

 @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

}

This is my search function

 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-search 标签下搜索时找到了解决我的问题的方法,有一个类似的情况,应该为三层嵌套关系建立索引,但我的只有 2 层,它起作用了,感谢这个人谁回答关于休眠搜索的每一个问题 Link:

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

不过有一个警告:由于 TextValueShort 没有对 UseSubCategory 的反向引用,您不能使用 @ContainedIn。这意味着对 TextValueShort 的更改不会触发 UseSubCategorySubCategoryUserManyToMany.

的重新索引

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

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