Применение одного и того же анализатора к запросам и полям - PullRequest
0 голосов
/ 20 января 2020

Я пытаюсь создать базовый c поиск для моего API-интерфейса. Пользователи передают произвольные запросы, и сервер должен возвращать результаты (очевидно). Я бы предпочел решение, которое работает как с локальным индексом, так и с Elasticsearch.

В своей сущности я определил анализатор следующим образом:

@AnalyzerDef(name = "ngram",
    tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class ),
    filters = {
      @TokenFilterDef(factory = StandardFilterFactory.class),
      @TokenFilterDef(factory = LowerCaseFilterFactory.class),
      @TokenFilterDef(factory = StopFilterFactory.class),
      @TokenFilterDef(factory = NGramFilterFactory.class,
        params = {
          @Parameter(name = "minGramSize", value = "2"),
          @Parameter(name = "maxGramSize", value = "3") } )
    }
)

Для запроса я попробовал следующее:

    FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(this.entityManager);
    Analyzer analyzer = fullTextEntityManager.getSearchFactory().getAnalyzer("ngram");

    QueryParser queryParser = new MultiFieldQueryParser(ALL_FIELDS, analyzer);
    queryParser.setDefaultOperator(QueryParser.AND_OPERATOR);
    org.apache.lucene.search.Query query = queryParser.parse(queryString);


    javax.persistence.Query persistenceQuery = 
            fullTextEntityManager.createFullTextQuery(query, MyEntity.class);

    List<MyEntity> result = persistenceQuery.getResultList();

Насколько я понимаю, мне нужно предоставить анализатор для запроса, чтобы поисковый запрос был "ngram-tokenized" и чтобы было найдено совпадение. Раньше я использовал SimpleAnalyzer, и в результате поиска соответствовали только полные слова, которые - я думаю, - подтверждают мою теорию (извините, я все еще изучаю это).

Приведенный выше код дает мне исключение NullPointerException:

java.lang.NullPointerException: null
        at org.hibernate.search.engine.impl.ImmutableSearchFactory.getAnalyzer(ImmutableSearchFactory.java:370) ~[hibernate-search-engine-5.11.1.Final.jar:5.11.1.Final]
        at org.hibernate.search.engine.impl.MutableSearchFactory.getAnalyzer(MutableSearchFactory.java:203) ~[hibernate-search-engine-5.11.1.Final.jar:5.11.1.Final]
        at org.hibernate.search.impl.SearchFactoryImpl.getAnalyzer(SearchFactoryImpl.java:50) ~[hibernate-search-orm-5.11.1.Final.jar:5.11.1.Final]

в строке

Analyzer analyzer = fullTextEntityManager.getSearchFactory().getAnalyzer("ngram");

1 Ответ

1 голос
/ 21 января 2020

Вы не можете извлечь анализатор из Hibernate Search при использовании интеграции Elasticsearch, потому что в этом случае анализатор не существует локально: анализатор существует только удаленно, в кластере Elasticsearch.

Если вам требуется только подмножество синтаксиса запроса, попробуйте запрос «простая строка запроса» : это запрос, который может быть построен с использованием DSL (поэтому он будет работать так же с Lucene и Elasticsearch) и который обеспечивает наиболее распространенные функции (логические запросы, нечеткость, фразы, ...). Например:

Query luceneQuery = queryBuilder.simpleQueryString()
    .onFields("name", "history", "description")
    .matching("war + (peace | harmony)")
    .createQuery();

Синтаксис немного отличается, но только потому, что он нацелен на конечных пользователей и пытается быть проще.

EDIT : если простой запрос Строки не являются опцией, вы можете создать анализатор вручную: это должно работать даже при использовании интеграции Elasticsearch. org.apache.lucene.analysis.custom.CustomAnalyzer#builder() должна быть хорошей отправной точкой. В javado c этого класса есть несколько примеров. Убедитесь, что вы создаете анализатор только один раз и сохраняете его где-то, например, в постоянной c: создание анализатора может быть дорогостоящим.

...