20 февр. 2018 г.
Это вторая статья из цикла про Elastic Search. Речь пойдет о настройках синонимов Elastic Search. Синонимы нужны в том случае, если у нас есть несколько слов, которые морфологически не похожи друг на друга, но при этом имеют сходное значение. Или это может быть профессиональный жаргон. Примеры: Углошлифовальная машина - болгарка, Отвертка - шуруповерт и т.д.
Все настройки проводились на Elastic Search 6.1.2. Запускалось в Docker.
docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.1.0-->
Проверка версии:
http://localhost:9200/
{ "name": "kPe0CUN", "cluster_name": "docker-cluster", "cluster_uuid": "htl0xwdDTgSzipAJgSfLmw", "version": { "number": "6.1.2", "build_hash": "5b1fea5", "build_date": "2018-01-10T02:35:59.208Z", "build_snapshot": false, "lucene_version": "7.1.0", "minimum_wire_compatibility_version": "5.6.0", "minimum_index_compatibility_version": "5.0.0" }, "tagline": "You Know, for Search" }
Впринципе это все должно так же работать и на других версиях, но возможны изменения.
Синонимы включаются в настройки индекса. Также есть возможность указать текстовый файл. Но мне этот вариант показался не таким удобным. Хотя, возможно, он имеет свои преимущества.
Создаем индекс:
curl -X PUT \ http://localhost:9200/product \ -H 'Content-Type: application/json' \ -d '{ "settings": { "analysis": { "filter": { "my_synonym_filter": { "type": "synonym", "synonyms": [ "шуруповерт, отвертка" ] }, "ru_stop": { "type": "stop", "stopwords": "_russian_" }, "ru_stemmer": { "type": "stemmer", "language": "russian" } }, "analyzer": { "my_synonyms": { "tokenizer": "standard", "filter": [ "lowercase", "my_synonym_filter", "ru_stop", "ru_stemmer" ] } } } } }'
Создаем маппинг
curl -X PUT \ http://localhost:9200/product/_mapping/type \ -H 'Cache-Control: no-cache' \ -H 'Content-Type: application/json' \ -H 'Postman-Token: 98d28f1a-665b-3e26-948b-10b789a6ffce' \ -d '{ "properties": { "id": { "type": "integer" }, "sku": { "type": "text", "index": true, "search_analyzer": "my_synonyms", "analyzer": "my_synonyms", "term_vector": "with_positions_offsets_payloads" }, "name": { "type": "text", "index": true, "search_analyzer": "my_synonyms", "analyzer": "my_synonyms", "term_vector": "with_positions_offsets_payloads" }, "description": { "type": "text", "index": true, "search_analyzer": "my_synonyms", "analyzer": "my_synonyms", "term_vector": "with_positions_offsets_payloads" }, "price": { "type": "double" }, "created_at": { "type": "text", "index": true, "search_analyzer": "my_synonyms", "analyzer": "my_synonyms", "term_vector": "with_positions_offsets_payloads" }, "updated_at": { "type": "text", "index": true, "search_analyzer": "my_synonyms", "analyzer": "my_synonyms", "term_vector": "with_positions_offsets_payloads" } } }'
Добавляем продукты:
curl -X PUT \ http://localhost:9200/product/type/1 \ -H 'Cache-Control: no-cache' \ -H 'Content-Type: application/json' \ -H 'Postman-Token: c99dcbcc-5f1f-4806-b941-db54d7fc2dfb' \ -d '{ "id": 1, "sku": "ИНТЕРСКОЛ ОА-3,6Ф", "name": "Отвертка аккумуляторная ИНТЕРСКОЛ ОА-3,6Ф блистер (433.0.2.00)", "description": "Отвертка аккумуляторная ИНТЕРСКОЛ ОА-3,6Ф блистер (433.0.2.00) li-ion Номинальное напряжение, В 3,6 Частота вращения, об/мин 210 Макс. Крутящий момент, Нм 5 Число ступеней регулировки крутящего момента 15+1 Масса, кг 0,5 Особенности: Технология Li-ion, Редуктор с металлическими пластинами, компактность, светодиодный фонарь, индикатор заряда, LED-подсветка.", "attribute_set_id": 4, "price": 100, "created_at": "2017-12-04 10:08:12", "updated_at": "2017-12-27 10:28:36" }'
curl -X PUT \ http://localhost:9200/product/type/2 \ -H 'Cache-Control: no-cache' \ -H 'Content-Type: application/json' \ -H 'Postman-Token: 93c262a5-6acc-b48c-4547-1596f2484534' \ -d '{ "id": 2, "sku": "Шуруповерт HAMMER", "name": "Шуруповерт HAMMER", "description": "Шуруповерт HAMMER", "attribute_set_id": 4, "price": 100, "created_at": "2017-12-04 10:08:12", "updated_at": "2017-12-27 10:28:36" }'
И так, у нас есть 2 продукта с разными названиями. Совпадений нет. Зато у нас есть настроенные синонимы. Пробуем искать по синонимам:
curl -X POST \ http://localhost:9200/product/type/_search \ -H 'Content-Type: application/json' \ -d '{ "query": { "multi_match": { "query": "Отвертка" } } }'
curl -X POST \ http://localhost:9200/product/type/_search \ -H 'Content-Type: application/json' \ -d '{ "query": { "multi_match": { "query": "Шуруповерт" } } }'
В обоих случаях возвращаются оба продукта. Значит синонимы работают корректно.
Вероятно в процессе работы нам захочется добавить новые синонимы. И, возможно, захочется делать это автоматически. Чтобы не нужно было перезапускать elastic, лезть в консоль, перезаливатьь данные, пересоздавать индекс и т.д.
Правда все же придется остановить индекс. Добавить синонимы, потом запустить снова. Но, к счастью, это происходит почти моментально.
Закрываем индекс:
curl -X POST \ http://localhost:9200/product/_close \ -H 'Content-Type: application/json' \
Обновляем синонимы
curl -X PUT \ http://localhost:9200/product/_settings \ -H 'Content-Type: application/json' \ -d '{ "settings": { "analysis": { "filter": { "my_synonym_filter": { "type": "synonym", "synonyms": [ "шуруповерт, шурик, отвертка" ] } } } } }'
Открываем индекс
curl -X POST \ http://localhost:9200/product/_open \ -H 'Content-Type: application/json' \
Мы добавили новый синоним "шурик" - жаргон. Теперь пробуем искать по нему.
curl -X POST \ http://localhost:9200/product/type/_search \ -H 'Cache-Control: no-cache' \ -H 'Content-Type: application/json' \ -H 'Postman-Token: d9d21a6d-07ff-9b29-e080-87f95c5ecddf' \ -d '{ "query": { "multi_match": { "query": "шурик" } } }'
Также возвращаются оба продукта. Обновление синонимов прошло успешно.
Все запросы из статьи оформлены в виде Postman коллекции. Скачать можно тут: elastic_synonyms.postman_collection.json
На этом пока все. Спасибо за внимание!