Elasticsearch - Как искать несколько слов в одной строке - PullRequest
0 голосов
/ 28 октября 2019

У меня проблемы с получением нужных мне результатов эластичного поиска.

Мои сопоставления выглядят так:

"mappings": {
    "product": {
        "_meta": {
            "model": "App\\Entity\\Product"
        },
        "dynamic_date_formats": [],
        "properties": {
            "articleNameSearch": {
                "type": "text",
                "analyzer": "my_analyzer"
            },
            "articleNumberSearch": {
                "type": "text",
                "fielddata": true
            },
            "brand": {
                "type": "nested",
                "properties": {
                    "name": {
                        "type": "text"
                    }
                }
            }
        }
    }
},

Мои настройки:

"settings": {
    "index": {
        "number_of_shards": "5",
        "provided_name": "my_index",
        "creation_date": "1572252785482",
        "analysis": {
            "filter": {
                "standard": {
                    "type": "standard"
                }
            },
            "analyzer": {
                "my_analyzer": {
                    "filter": [
                        "standard"
                    ],
                    "type": "custom",
                    "tokenizer": "lowercase"
                }
            }
        },
        "number_of_replicas": "1",
        "uuid": "bwmc7NZ9RXqB1lpQ3e8HTQ",
        "version": {
            "created": "5060399"
        }
    }
}

Данныеinside:

"hits": [
  {
    "_index": "my_index",
    "_type": "product",
    "_id": "14",
    "_score": 1.0,
    "_source": {
      "articleNumberSearch": "5003xx843",
      "articleNameSearch": "this is a test string",
      "brand": {
        "name": "Brand name"
      }
    }
},

В настоящее время код PHP для запроса выглядит следующим образом (это не возвращает правильные записи):

$searchQuery = new BoolQuery();
$formattedQuery = "*" . str_replace(['.', '|'], '', trim(mb_strtolower($query))) . "*"; 

/**
 * Test NGRAM analyzer
 */
$matchQuery = new Query\MultiMatch();
$matchQuery->setFields([
    'articleNumberSearch',
    'articleNameSearch',
]);
$matchQuery->setQuery($formattedQuery);
$searchQuery->addMust($matchQuery);


/**
 * Nested query
 */
$nestedQuery = new Nested();
$nestedQuery->setPath('brand');
$nestedQuery->setQuery(
    new Match('brand.name', 'Brand name')
);
$searchQuery->addMust($nestedQuery);

Я создаю и автоматически заполняю поле поиска,где вы можете искать articleNumberSearch и articleNameSearch, в то время как название бренда всегда является фиксированным значением.

Я хочу иметь возможность искать, например: 500 найдет этот хит, потому что 500 находится в articleNumberSearch.

Но также можно искать: this is string

Пара вопросов:

  • Какой запрос мне нужно использовать?
  • Amя использую правильный анализатор?
  • Правильно ли настроен мой анализатор?

1 Ответ

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

Вы должны создать токенизатор типа ngram.

Токенизатор ngram сначала разбивает текст на слова всякий раз, когда встречается с одним из списка указанных символов.

Примерно так:

"analysis": {
    "analyzer": {
       "autocomplete": {
           "filter": [
            "lowercase"
           ],
           "type": "custom",
           "tokenizer": "my_tokenizer"
       }
   },
   "tokenizer": {
       "my_tokenizer": {
           "token_chars": [
               "letter",
               "digit",
               "symbol",
               "punctuation"
           ],
           "min_gram": "1",
           "type": "ngram",
           "max_gram": "2"
      }
   }
}

NGram Tokenizer

enter image description here

...