Hibernate Поиск с nGram | Как указать, что nGram не делает граммы во время поиска - PullRequest
0 голосов
/ 10 мая 2019

Я определил свой анализатор, как показано ниже

@AnalyzerDefs({
@AnalyzerDef(name = "ngram",
            tokenizer = @TokenizerDef(factory = KeywordTokenizerFactory.class),
            filters = {
                    //@TokenFilterDef(factory = StandardFilterFactory.class),
                    @TokenFilterDef(factory = LowerCaseFilterFactory.class),
                    @TokenFilterDef(factory = NGramFilterFactory.class, params = {
                            @Parameter(name = "minGramSize", value = "3"),
                            @Parameter(name = "maxGramSize", value = "255") }) }),
//-----------------------------------------------------------------------
    @AnalyzerDef(name = "ngram_query",
            tokenizer = @TokenizerDef(factory = KeywordTokenizerFactory.class),
            filters = {
                    //@TokenFilterDef(factory = StandardFilterFactory.class),
                    @TokenFilterDef(factory = LowerCaseFilterFactory.class)
                    }) 
})

@Analyzer(definition = "ngram")
public class EPCAsset extends Asset {
    @Field
    private String obturatorMaterial;

}

Прекрасно делает n-граммы векторов слагаемых в течение индексного времени. Но он также делает n-грамм поискового запроса во время поиска.

То, что я хочу, - это способ, с помощью которого поисковый запрос использует индекс n-грамм для поиска, не разбивая поисковый термин на граммы.

Примечание: здесь я должен использовать n-грамм, потому что требуется искать в любом месте текста. либо в начале, либо в середине. так что ребро-н-грамм для меня не вариант.

Пример: Входные данные для индексации ICQ 234

Тогда во время индекса его векторы-члены будут

    "234"
    " 23"
    " 234"
    "cq "
    "cq 2"
    "cq 23"
    "cq 234"
    "icq"
    "icq "
    "icq 2"
    "icq 23"
    "icq 234"
    "q 2"
    "q 23"
    "q 234"

Теперь, когда я ищу icq , он работает отлично. Но это также работает для icqabc , так как во время поиска он делает n-грамм поискового запроса. Так есть ли способ, чтобы во время поиска он не нарушал поисковый запрос, а использовал индекс n-граммы для поиска.

Вот мое здание поискового запроса

FullTextEntityManager fullTextEntityManager = Search
            .getFullTextEntityManager(entityManager);

QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder()
            .forEntity(entityClass).get();
Query query = qb.phrase().onField("obturatorMaterial").sentence("icqabc").createQuery();
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(query,
            entityClass);
fullTextQuery.getResultList()

Я использую эластичный поиск в качестве бэкенда для поиска в Hibernate.

EDIT: Я также применил анализатор времени запроса согласно ответу @ yrodiere, но он дает мне ошибку.

QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder()
            .forEntity(entityClass).overridesForField("obturatorMaterial","ngram_query").get();

org.hibernate.search.exception.SearchException: HSEARCH000353: Неизвестный анализатор: 'ngram_query'. Убедитесь, что вы определили этот анализатор.

EDIT

По этой ссылке overriderForField при использовании гибернационного поиска с поддержкой эластичного поиска

Теперь я могу определить время запроса 2-го анализатора, и это решило проблему.

Ответы [ 2 ]

1 голос
/ 10 мая 2019

Во-первых, вы должны дважды проверить, что фильтр Ngram действительно то, что вы хотите.Я упоминаю об этом, потому что анализатор ngram обычно используется как при индексации, так и при запросах, так что он обеспечивает нечеткие совпадения.В этом вся суть этого анализатора.

Вам действительно нужны совпадения, когда пользователь вводит cq 2?Имеет ли это смысл?При реализации автозаполнения люди обычно предпочитают сопоставлять только документы, содержащие слова, которые начинаются с с пользовательским вводом, поэтому i будет соответствовать ic и icq, но не cq 2.Если это то, что вам нужно, вы должны взглянуть на фильтр "edge_ngram".Он имеет тенденцию улучшать релевантность совпадений, а также не требует много места на диске.

Теперь, даже с фильтром "edge_ngram", вам нужно будет отключить ngrams во время запроса.В Hibernate Search это делается путем «переопределения» анализатора.

  1. Сначала определите второй анализатор, идентичный тому, который вы используете во время индексации, но без фильтра «ngram» или «edge_ngram»,Назовите его «ngram_query».
  2. Затем используйте его для создания построителя запросов:

    QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(EPCAsset.class)
        .overridesForField( "obturatorMaterial", "ngram_query" )
        .get();
    
  3. Используйте построитель запросов, чтобы создать свой запрос как обычно.

Обратите внимание, что если вы используете Hibernate Search для передачи схемы индекса и анализаторов в Elasticsearch, вам придется использовать хак для того, чтобы анализатор только для запросов выдвигался: по умолчанию только анализаторыкоторые фактически используются во время индексации.См https://discourse.hibernate.org/t/cannot-find-the-overridden-analyzer-when-using-overridesforfield/1043/4

1 голос
/ 10 мая 2019

Либо вам нужно использовать анализатор времени поиска , и весьма вероятно, что это будет анализатор ключевых слов во время поиска.Или нужно использовать term запрос вместо match запроса, который анализируется, означает, что он использует тот же индекс времени, использованный анализатором.

Подробнее о term query и matchзапрос для получения дополнительной информации.

Edit : - https://www.elastic.co/guide/en/elasticsearch/reference/current/search-analyzer.html четко говорил об использовании search_analyzer , в случае edgeNGramтокенизатор и автозаполнение поиска , который является именно вашим вариантом использования.

...