Запрос Hibernate Search извлекает данные из фактической базы данных, а не из индексов Elastic DB

Мы пытаемся реализовать в нашем проекте эластичный поиск. До сих пор мы умеем создавать индексы под ES. Но проблема в поиске. Когда мы запускаем запрос для извлечения данных, запрос запускается в фактической базе данных, а не в индексах ES DB.

hibernate.cfg

<property name = "hibernate.search.default.indexmanager">elasticsearch</property>
<property name = "hibernate.search.default.elasticsearch.host">http://127.0.0.1:9200</property>
<property name = "hibernate.search.default.elasticsearch.index_schema_management_strategy">drop-and-create</property>
<property name = "hibernate.search.default.elasticsearch.required_index_status">yellow</property>

Код для поиска:

 Session session = HibernateSessionFactory.current().getSession("");
      fullTextSession = Search.getFullTextSession(session.getSession());
      searchFactory = fullTextSession.getSearchFactory();

QueryBuilder titleQB = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(<MyClassHere>.class).get();

    Query query = titleQB.phrase().onField(EMAIL1_EDGE_NGRAM_INDEX).andField(EMAIL1_NGRAM_INDEX)
            .boostedTo(5).sentence(searchTerm.toLowerCase()).createQuery();

    FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery(query, <MyClassHere>.class);
    fullTextQuery.setMaxResults(20);

    List<Bascltj001TO> results = fullTextQuery.getResultList();
    return results;

Класс сущности:

@Entity
@Indexed
public class MYClass {
    private DBAccessStatus dBAccessStatus;
    private String optname = "";
    private String phone1 = "";
    @Fields({
          @Field(name = "email1", index = Index.YES, store = Store.YES,
        analyze = Analyze.YES, analyzer = @Analyzer(definition = "standardAnalyzer")),
          @Field(name = "edgeNGramEmail1", index = Index.YES, store = Store.NO,
        analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteEdgeAnalyzer")),
          @Field(name = "nGramEmail1", index = Index.YES, store = Store.NO,
        analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteNGramAnalyzer"))
        })
    private String email1 = "";

Данные эластичного БД json

{
        "_index" : "myclass",
        "_type" : "myclass",
        "_id" : "67",
        "_score" : 1.0,
        "_source" : {
          "id" : "67",
          "cltseqnum" : 67,
          "email1" : "[email protected]",
          "edgeNGramEmail1" : "[email protected]",
          "nGramEmail1" : "[email protected]"
        }

Определения анализатора

@AnalyzerDefs({

        @AnalyzerDef(name = "autocompleteEdgeAnalyzer",

// Split input into tokens according to tokenizer
                tokenizer = @TokenizerDef(factory = KeywordTokenizerFactory.class),

                filters = {
                        // Normalize token text to lowercase, as the user is unlikely to
                        // care about casing when searching for matches
                        @TokenFilterDef(factory = PatternReplaceFilterFactory.class, params = {
                                @Parameter(name = "pattern", value = "([^a-zA-Z0-9\\.])"),
                                @Parameter(name = "replacement", value = " "),
                                @Parameter(name = "replace", value = "all") }),
                        @TokenFilterDef(factory = LowerCaseFilterFactory.class),
                        @TokenFilterDef(factory = StopFilterFactory.class),
                        // Index partial words starting at the front, so we can provide
                        // Autocomplete functionality
                        @TokenFilterDef(factory = EdgeNGramFilterFactory.class, params = {
                                @Parameter(name = "minGramSize", value = "3"),
                                @Parameter(name = "maxGramSize", value = "50") }) }),

        @AnalyzerDef(name = "autocompleteNGramAnalyzer",

// Split input into tokens according to tokenizer
                tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),

                filters = {
                        // Normalize token text to lowercase, as the user is unlikely to
                        // care about casing when searching for matches
                        @TokenFilterDef(factory = WordDelimiterFilterFactory.class),
                        @TokenFilterDef(factory = LowerCaseFilterFactory.class),
                        @TokenFilterDef(factory = NGramFilterFactory.class, params = {
                                @Parameter(name = "minGramSize", value = "3"),
                                @Parameter(name = "maxGramSize", value = "5") }),
                        @TokenFilterDef(factory = PatternReplaceFilterFactory.class, params = {
                                @Parameter(name = "pattern", value = "([^a-zA-Z0-9\\.])"),
                                @Parameter(name = "replacement", value = " "),
                                @Parameter(name = "replace", value = "all") }) }),
0
0
389
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ваш запрос представляет собой полнотекстовый запрос, поэтому он будет выполняться в кластере Elasticsearch - Hibernate Search не может преобразовать его в запрос к базе данных.

Но ... имейте в виду, что ваш индекс не включает все необходимые данные для построения сущностей. Таким образом, после получения идентификаторов из кластера Elasticsearch, Hibernate Search выполнит запрос к вашей базе данных, чтобы получить результаты в виде сущностей.

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

Спасибо, Гийом, за быстрый ответ. Не могли бы вы уточнить последний пункт: «Обычно получение ваших сущностей - это то, что вы хотите».

ronak 10.08.2018 13:52

Я предполагаю, что вы видите, что он выполняет запрос на оба. Конечно, он не будет запускать запрос только к базе данных, так как такой полнотекстовый запрос невозможно выполнить в базе данных.

Архитектура по умолчанию

По умолчанию FullTextQuery запускает запрос в Elasticsearch, чтобы узнать первичные ключи совпадающих объектов, а затем использовать этот список идентификаторов для загрузки полностью управляемых объектов домена из базы данных.

Обычно это то, чего хотят люди, чтобы убедиться, что вы получаете последнюю версию данных и что объекты загружаются в безопасной области транзакции.

Также он позволяет применять изменения к объектам и применять эти изменения как к вашей базе данных, так и к кластеру Elasticsearch при фиксации транзакции.

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

Альтернативные варианты

Если по какой-либо причине вы просто хотите выполнить запрос исключительно в Elasticsearch, вам просто нужно использовать прогнозы.

Видеть:

Прогнозы сделали свое дело. Спасибо, Санне и Гийом. Так же, как в ответе Санне была ссылка на решение, помеченная как ответ :) Ниже приведен обновленный код поискового запроса: fullTextQuery.setMaxResults (20) .setProjection (ElasticsearchProjectionConstants.SCORE, ElasticsearchProjectionConstants.SOURCE);

ronak 10.08.2018 14:22

Другие вопросы по теме