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
На этом пока все. Спасибо за внимание!