2013-02-02 03 Голушко. Полнотекстовый поиск с elasticsearch
DESCRIPTION
TRANSCRIPT
Дмитрий Голушко
О докладчике
Java разработчик, server-side
Важные параметры:
Скорость индексирования(в том числе realtime)
Способы взаимодействия(API, REST, etc.)
Работа с языками, стемминг, нечеткие запросы
Дополнительные типы полей в документах(numeric, geo, source, etc.)
Платформа и язык
Встроенные механизмы ранжирования и сортировки
Какие есть варианты?
Elasticsearch(based on Lucene, Java)
Solr(based on Lucene, Java)
Sphinx search engine(C++)
Xapian(C++)
Почему мы выбрали Elasticsearch?
Отличная поддержка шардинга и репликации на лету
Шардинг и репликация. Создаем индекс.
Нода 1
Street1
Street2
{ “number_of_shards” : 2, “number_of_replicas” : 1 }
Шардинг и репликация. Добавляем еще одну ноду.
Нода 1 Нода 2
Street1 Street1
Street2 Street2
Репликация
Шардинг и репликация. Добавляем еще 2 ноды.
Нода 1 Нода 2
Street1
Street2
Нода 3 Нода 4
Street1
Street2
Почему мы выбрали Elasticsearch?
Написан на Java и базируется на известном движке Lucene
Отличная поддержка шардинга и репликации на лету
Near-realtime индексация.
Поиск по «свежему» индексу
Поиск по индексу, с одновременной индексацией
Поиск по большому индексу, с одновременной индексацией
Почему мы выбрали Elasticsearch?
Написан на Java и базируется на известном движке Lucene
Отличная поддержка шардинга и репликации на лету
Near-realtime индексация.
Есть всё что нам нужно
Имеется возможность для расширения
Opensource, ASL v2
Возможность для расширения
River-плагины(поток данных из другого источника)
CouchDB RabbitMQ MongoDB
Анализаторы
…
Русская морфология Hunspell(орфография)
… Transport(расширения протоколов взаимодействия)
Memcached ZeroMQ Servlet
Site Plugins(чаще всего UI для управления кластером)
Scripting Plugins(ЯП для скриптов)
ElasticSearch Paramedic
BigDesk
elasticsearch-head
Особенности Elasticsearch
Документно-ориентированный
Schema-free
JSON как основной способ работы с данными
JSON как основной способ работы с данными
GET “http://localhost:9200/index_name/streets/_search?q=Жукова”
{ "took" : 138, "timed_out" : false, "_shards" : { "total" : 2, "successful" : 2, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 1.9674579, "hits" : [{ "_index" : “index_name", "_type" : "street", "_id" : "VLvO7h7bQUiCOlGwd2iJrA", "_score" : 1.9674579, "_source" : {"STREET_NAME":"Маршала Жукова", "CITY_NAME":"Омск", “STREET_ID” : 3} } ] } }
Затраченное время
Количество результатов
Исходный документ
Особенности Elasticsearch
Документно-ориентированный
Schema-free
JSON как основной способ работы с данными
Распределенный поиск
Распределенный поиск
Node Node Node
Node Node Node
Приложение
Распределенный поиск
Node Node Node
Node Node Node
Приложение
Особенности Elasticsearch
Документно-ориентированный
Schema-free
JSON как основной способ работы с данными
Распределенный поиск
Скрипты для фильтрации(о них чуть позже)
Обновление настроек «на лету»
Обновление настроек «на лету»
"{ "index" : { "number_of_replicas" : 3 } }
POST “http://localhost:9200/index_name/_settings”
Обновление настроек на лету
Нода 1 Нода 2
Street1
Street2
Нода 3 Нода 4
Street1
Street2 Street2 Street2
Street1 Street1
Индексация
Анализатор
Tokenizer
Token Filter
Token Filter
Token Filter
Token Filter
Token Filters
Фонетические(Soundex, Metaphone, etc.)
Стеммеры(Стеммер Портера)
Ngramm
важно важного важное важной важном важному
важн важн важн важн важн важн
Soundex • Первая буква сохраняется • В остальной части слова:
• Буквы, обозначающие, как правило, гласные звуки: a, e, h, i, o, u, w и y — отбрасываются • Оставшиеся буквы (согласные) заменяются на цифры от 1 до 6, причём похожим по звучанию буквам соответствуют одинаковые цифры:
• 1: b, f, p, v • 2: c, g, j, k, q, s, x, z • 3: d, t • 4: l • 5: m, n • 6: r
• Любая последовательность одинаковых цифр сокращается до одной такой цифры. • Итоговая строка обрезается до первых четырёх символов. Если длина строки меньше требуемой, недостающие символы заменяются знаком 0. Примеры: аmmonium → ammnm → a5555 → a5 → a500 implementation → implmnttn → i51455335 → i514535 → i514
Ngramm
Запросы
«Обычные» запросы Term Match\Not match Bool Prefix Wildcard Range
Нечеткие запросы
Географические запросы
Boosting запросы
Span запросы
Fuzzy запросы(нечеткие)
Расстояние Левенштейна - минимальное количество операций
вставки одного символа, удаления одного символа и замены одного символа на другой, необходимых для превращения одной строки в другую.
Жукава Жукова
Лизной (проезд) Лесной (проезд)
Бухольца Бухгольца
1
2
1
Это важно! В большинстве случаев вы должны использовать для поиска
тот же алгоритм анализа, что и при индексировании!
Fuzzy Query «жукава»
Soundex «a500»
3gramm «жук ука кав ава»
Fuzzy Query «жукава»
Фильтрация
Обычные фильтры
Геофильтры
Script фильтр
Term Prefix Range Missing\Exists Query
Геофильтры
Geo distance Geo distance range Geo polygon Geo shape Geo BBox
{ “address" : { "location" : { "lat" : 41.12, "lon" : -71.34 } } }
{ "location" : { "type" : "envelope", "coordinates" : [[-45.0, 45.0], [45.0, -45.0]] } }
Геофильтры
Geo distance Geo distance range Geo polygon Geo shape Geo BBox
"filter" : { "geo_bounding_box" : { "pin.location" : { "top_left" : {"lat" : 40.73, "lon" : -74.1 }, "bottom_right" : {"lat" : 40.717, "lon" : -73.99} } } }
Геофильтры
Geo distance Geo distance range Geo polygon Geo shape Geo BBox
Геофильтры
Geo distance Geo distance range Geo polygon Geo shape Geo BBox
"filter" : { "geo_distance" : { "distance" : "2km", "pin.location" : { "lat" : 40, "lon" : -70 } } }
Геофильтры
Geo distance Geo distance range Geo polygon Geo shape Geo BBox
Геофильтры
Geo distance Geo distance range Geo polygon Geo shape Geo BBox
"filter": { "geo_shape": { "location": { "indexed_shape": {"id": "Украина", "type": "countries", "index": "shapes", "shape_field_name": "shape" }, "relation": "within" } } }
Скрипт-фильтр
"filtered" : { "query" : { ... }, "filter" : { "script" : { "script" : "doc['num1'].value > 1" } } }
Скрипт-фильтр. Доступные языки
Java
Groovy
Python
JavaScript
Advanced features Подсветка(Highlighting)
Именованные фильтры(Named Filters)
Percolation
Facets
Attachment indexing(с помощью Apache Tika) Microsoft Office, Open Document Formats, ePub, PDF, etc.
Time-to-live fields
Percolation
Индексируются запросы, а не документы!
Тем не менее это обычный индекс
Запросы распространяются на все реплики
Поддерживают все обычные запросы и фильтры
Percolation
{ "query" : { "terms" : {
"message" : ["путин","навальный", "террорист","бомба", "наркотики","взятка"]
} } }
“http://localhost:9200/_percolator/messages/kgb” POST
{"ok":true, "matches":["kgb"]}
Здарова! Зацени чо творится «Одесский террорист, "метивший в Путина", заявил о милицейских пытках наркотиками и пакетами».
"doc" : { "message" : "..." }
“http://localhost:9200/messages/type/_percolate” GET
Facets
Агрегированная информация по запросу
Статистическая информация Сумма, минимальное\максимальное значение, среднее и т.д.
Гистограммы(включая гистрограмму по дате)
Географический facet
Географический facet { "facets" : { "geo1" : { "geo_distance" : { "pin.location" : {"lat" : 40, "lon" : -70 }, "ranges" : [ { "to" : 10 }, { "from" : 10, "to" : 20 }, { "from" : 20, "to" : 100 }, { "from" : 100 } ] } } } }
А теперь небольшой real-world пример!
Развлечения!
{ "query" : { "match_all" : {} }, "facets" : { "facet_search" : { "terms" : { "quick_address_type" : ["restaurant", "cafe", "sauna", "pool", "bowling","bar"] } } } }
"facets" : { "tags" : { "_type" : "terms", "missing" : 0, "total": 30, "other": 0, "terms" : [ { "term" : "restaurant", "count" : 7 }, {"term" : "cafe", "count" : 5 }, {"term" : "sauna","count" : 6}, {"term" : "pool","count" : 3}, {"term" : "bowling","count" : 2}, {"term" : "bar","count" : 7 } ] } }
Рестораны(7)
Кафе(5)
Сауны(6)
Боулинги(2)
Бильярды(3)
Бары(7)
{ "query" : { "term" : {"quick_address_type" : "restaurant"} }, "sort" : [ { "_geo_distance" : { "pin.location" : [-73.13, 55.01], "order" : "asc", "unit" : "km" } }, { "rating" : { "user_rating" : "desc" } } ] }
«Беляшкино» 1км.
«Пампуши» 2км.
«Фуаграшная» 0,5км.
КОНЕЦ!