Как добиться полнотекстового поиска для вложенных глубоко вложенных объектов с помощью Apache Lucene? в загрузочном проекте Spring - PullRequest
0 голосов
/ 15 октября 2019

Я новичок в Apache Lucene или любых других движках fts, так что извините за это Я успешно внедрил Apache Lucene вместе с поисковой формой гибернации, НО, когда дело доходит до вложенных отношений, это работает только одинслой вниз, пока я понял и пытался до сих пор. Таким образом, я могу добиться поиска более двух вложенных объектов, вложенных ниже, например:

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

Как вы можете видеть, у меня есть заголовокполе, которое является другим отношением, на котором должно быть выполнено 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())
    }

Как вы можетеу меня есть e "subCategory.title.en", который выдает исключение

Ответы [ 2 ]

1 голос
/ 15 октября 2019

UseSubCategory.title не индексируется. Чтобы проиндексировать его, добавьте @IndexedEmbedded к этому свойству, как вы сделали для SubCategoryUserManyToMany.title, и добавьте @Field аннотации к различным свойствам TextValueShort (en, ru, ...).

Одно предупреждение: поскольку TextValueShort не имеет обратной ссылки на UseSubCategory, вы не можете использовать @ContainedIn. Это означает, что изменения в TextValueShort не приведут к повторной индексации UseSubCategory и SubCategoryUserManyToMany.

. Существует три решения этой проблемы:

  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
0 голосов
/ 15 октября 2019

Я нашел решение своей проблемы, просто выполняя поиск по тегу hibernate-search, был похожий случай, в котором должны быть проиндексированы три многослойных вложенных отношения, но у меня было только 2 слоя, и это сработало, спасибо человеку, который отвечаеткаждый вопрос относительно hibernate-search Link: yrodiere's answer

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...