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.
На этом пока все. В следующих статьях планирую рассказать о настройке морфологического поиска и синонимов. Спасибо за внимание!