31 янв. 2018 г.
На текущем проекте используем Elastic Search. Elastic представляет собой движок для продвинутого поиска по документам. Основан на Apache Solr. По сути, является NoSQL хранилищем, и некоторые даже используют его, как отдельную БД.
За время работы нашлось несколько вещей, которые не сразу удалось настроить. Информации в сети много, но местами она не очень структурирована, либо есть различия для разных версий. Либо просто сразу не удается найти нужный материал. В результате пришлось перелопатить весь интернет, прежде чем все заработало как требовалось.
Это первая статья из цикла. Здесь все тривиально, речь пойдет о базовых настройках Elastic Search.
Установить elastic search на ubuntu можно по этому руководству.
Или через docker.
docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.1.0 -->
Вариант с установкой через docker мне понравился гораздо больше т.к. сам процесс гораздо проще. Можно без труда установить любую актуальную версию. Не надо вносить изменения в хост систему. Вообще, всем рекомендую. Сначало немного сложно, но потом очень удобно.
Предыдушие версии Elastic search можно найти здесь: https://hub.docker.com/_/elasticsearch/ Например, elastic 5.6 запускается такой командой:
docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:5.6.5
Чтобы проверить работоспособность, достаточно открыть в браузере: http://localhost:9200/
И увидеть что-то такое:
{
"name": "s47BTOo",
"cluster_name": "docker-cluster",
"cluster_uuid": "G_58RLKfS4C3ZbxnEpfdiw",
"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"
}
Далее в статье я буду использовать elastic search 6.1.2. Для других версий настройки могут немного отличаться.
Дальше нужно добавить индекс. Впринципе, этот шаг можно пропустить и сразу приступить к добавлению данных. Но для серьезного использования рекомендую все же сначала добавить индекс. Так мы можем задать его настройки, например, морфологию.
Чтобы создать индекс, нужно выполнить такой запрос:
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"
]
}
}
}
}
}'
Ответ должен быть примерно таким:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "product"
}
Далее добавляем mapping:
curl -X PUT \
http://localhost:9200/product/_mapping/type \
-H 'Content-Type: application/json' \
-d '{
"properties": {
"id": {
"type": "integer"
},
"sku": {
"type": "text",
"index": true,
"fielddata": true,
"search_analyzer": "my_synonyms",
"analyzer": "my_synonyms",
"term_vector": "with_positions_offsets_payloads"
},
"name": {
"type": "text",
"index": true,
"fielddata": true,
"search_analyzer": "my_synonyms",
"analyzer": "my_synonyms",
"term_vector": "with_positions_offsets_payloads"
},
"description": {
"type": "text",
"index": true,
"fielddata": true,
"search_analyzer": "my_synonyms",
"analyzer": "my_synonyms",
"term_vector": "with_positions_offsets_payloads"
},
"price": {
"type": "double"
},
"created_at": {
"type": "text",
"index": true,
"fielddata": true,
"search_analyzer": "my_synonyms",
"analyzer": "my_synonyms",
"term_vector": "with_positions_offsets_payloads"
},
"updated_at": {
"type": "text",
"index": true,
"fielddata": true,
"search_analyzer": "my_synonyms",
"analyzer": "my_synonyms",
"term_vector": "with_positions_offsets_payloads"
}
}
}'
Здесь мы указывем все поля, типы данных и правила обработки для них. Ответ должен быть примерно таким:
{
"acknowledged": true
}
После того, как мы настроили индекс и маппинг, можно приступить к загрузке данных. Если индекс/маппинг не существует, то он будет создан автоматически. Добавим запись в elastic search. Выполним такой запрос:
curl -X PUT \
http://localhost:9200/product/type/1 \
-H 'Content-Type: application/json' \
-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"
}'
В результате, продукт добавлен в elastic search:
{
"_index": "product",
"_type": "type",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
Получить запись по id можно так:
http://localhost:9200/product/type/1
Получить все записи в индексе можно таким запросом:
http://localhost:9200/product/_search?pretty=true&q=*:*
Для более презентативных результатов рекомендую добавить еще несколько(десятков) записей. Хотя, общий принцип можно понять и с двумя записями. Поиск по одному полю:
curl -X POST \
http://localhost:9200/product/type/_search \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-H 'Postman-Token: 51c27b84-a128-3d52-aa0e-67f2925c0f28' \
-d '{
"query": {
"match": {
"sku": "Интерскол"
}
}
}
'
Поиск по всем полям:
curl -X POST \
http://localhost:9200/product/type/_search \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-H 'Postman-Token: 96ccd985-80cc-835b-885f-0ced99b839c6' \
-d '{
"query": {
"multi_match" : {
"query": "Отвертка"
}
}
}
'
Пагинация:
curl -X POST \
http://localhost:9200/product/type/_search \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-H 'Postman-Token: f698e45a-4680-ae18-554f-a64f3dbbdc44' \
-d '{
"from" : 0, "size" : 10,
"query": {
"match": {
"sku": "Интерскол"
}
}
}
'
Сортировка:
curl -X POST \
http://localhost:9200/product/type/_search \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-H 'Postman-Token: 91153d43-0ee7-b1d3-a283-2043bed98772' \
-d '{
"sort" : {
"sku": {
"order": "asc",
"mode": "min"
}
},
"_source": ["id", "sku","name"],
"size": 2
}
'
Для корректной работы сортировки нужен настроеный индекс и маппер.
Если все надоело, можно удалить все данные и попробовать снова:
curl -X DELETE \
http://localhost:9200/_all \
Либо можно перезапустить docker контейнер. Тогда все данные и настройки сбросятся.
Все запросы из статьи оформлены в виде Postman коллекции. Скачать можно тут: elastic-demo-part1.postman_collection.json.
На этом пока все. В следующих статьях планирую рассказать о настройке морфологического поиска и синонимов. Спасибо за внимание!