sphinx — универсальное средство поиска

32
Sphinx — универсальное средство поиска Interlabs 9 января 2014 1 / 32

Post on 15-Nov-2014

2.196 views

Category:

Technology


2 download

DESCRIPTION

Очередной семинар был посвящен средствам фильтрации результатов поиска поискового сервера Sphinx. Были рассмотрены методы отладки поисковых поисковых запросов, особенности языка SphinxQL, варианты фильтрации произвольного набора атрибутов в схеме EAV и реализация фасетного поиска.

TRANSCRIPT

Page 1: Sphinx — универсальное средство поиска

Sphinx — универсальноесредство поиска

Interlabs

9 января 2014

1 / 32

Page 2: Sphinx — универсальное средство поиска

О чем речь

• Sphinx — не только для полнотекстового поиска• real-time индексы для экспериментов со Sphinx• различные виды атрибутов и как их использовать• Sphinx и E.A.V.• Faceted Search на Sphinx

2 / 32

Page 3: Sphinx — универсальное средство поиска

Индекс Sphinxid + поля + атрибуты

id уникальный идентификатор документаполе полнотекстовый поиск, хранится только индекс

атрибут поиск по значению, хранится значение

Атрибуты: Integer, Float, Bool, Timestamp, MVA, String, JSON

disk index или realtime index

disk изменяется полным перестроениемrealtime изменения явно добавляются в индекс

3 / 32

Page 4: Sphinx — универсальное средство поиска

Дисковый индекс

• использует источник данных (data source)• обновление индекса = его перестроение• построение не требует поддержки в коде приложения• повышенная нагрузка на источник данных приперестроении

Время и нагрузку от перестроения можно оптимизировать засчет использования дельта-индексов только для последнихизменений.

4 / 32

Page 5: Sphinx — универсальное средство поиска

Структура индекса

.spd document lists (aka doclists)

.spp keyword positions lists (aka hitlists)

Загружаются в память:

.sph header file.spi dictionary (aka wordlist).spa attribute values.spm MVA values.spk kill list (aka klist)

5 / 32

Page 6: Sphinx — универсальное средство поиска

Источник SQLMySQL, PostgreSQL, MS SQL, ODBC

• результат выполнения SQL-запроса• структура индекса жестко задана в конфигурации

source sql_source{

type = mysqlsql_host = localhost...sql_query = SELECT id, ts, category, title, body ...sql_attr_uint = categorysql_attr_timestamp = ts...

}

6 / 32

Page 7: Sphinx — универсальное средство поиска

Источник xmlpipe2• вывод произвольной команды в стандартном XML• структура индекса определяется содержимым XML

source xmlsrc{

type = xmlpipe2xmlpipe_command = /usr/bin/php /path/to/script.php

}

Использование

• данные не из реляционной БД• невозможно получить данные из БД одним запросом• нужно менять состав индекса без изменения конфигурации

7 / 32

Page 8: Sphinx — универсальное средство поиска

xmlpipe2: данные<?xml version="1.0" encoding="utf-8"?><sphinx:docset>

<sphinx:schema><sphinx:field name="subject"/><sphinx:field name="content"/><sphinx:attr name="published" type="timestamp"/><sphinx:attr name="author_id" type="int" bits="16" default="1"/>

</sphinx:schema>

<sphinx:document id="1234"><content>this is the main content <![CDATA[[and this <cdata> entry

must be handled properly by xml parser lib]]></content><published>1012325463</published><subject>note how field/attr tags can be

in <b class="red">randomized</b> order</subject><misc>some undeclared element</misc>

</sphinx:document>...

8 / 32

Page 9: Sphinx — универсальное средство поиска

Realtime index

• источник данных отсутствует• данные для индексирования явно добавляются в индексприложением

• добавление, удаление и изменение может быть выполненов любой момент времени и сразу становится доступным

• производительность близка к производительностидискового индекса

• работа с realtime-индексом ничем не отличается от работыс дисковым индексом

• удобно для различных экспериментов со SphinxQL

9 / 32

Page 10: Sphinx — универсальное средство поиска

Атрибуты

Хранятся в индексе, не участвуют в полнотекстовом поиске, нопозволяют фильтровать его результаты:

uint 1-bit — 32-bittimestamp UNIX timestamp

float 32-bitstring до 4MB но загружаются в памятьMVA набор целочисленных идентификаторов,

кешируется в памятиJSON произвольные JSON-данные, также расход памяти

10 / 32

Page 11: Sphinx — универсальное средство поиска

Потребление памятиДисковый индекс:

• общий объем файлов индекса минус .spd и .spp.

Real-time индекс:

• память выделяется фрагментами, rt_mem_limit.• фрагмент заканчивается — записывается на диск ивыделяется следующий.

• по умолчанию 128M.

SHOW INDEX indexname STATUS

11 / 32

Page 12: Sphinx — универсальное средство поиска

SphinxQL

Язык запросов к индексам Sphinx, совместимый с SQL

• доступен по протоколу MySQL• можно использовать любой MySQL клиент• MySQL сервер не нужен• индексы в виде таблиц, SELECT для построения запросов• команды для дополнительной информации о результате• очень похож на SQL, но есть различия

12 / 32

Page 13: Sphinx — универсальное средство поиска

Минимальная конфигурация

index test # тестовый индекс{ # доступен в виде таблицы SphinxQL

type = rt # real-time indexpath = /path/to/index/files # путь к каталогу с файлам индексаrt_field = title # полеrt_attr_multi = categories # MVA-атрибутrt_attr_json = attributes # JSON-атрибут

}

searchd{

listen = 9306:mysql41 # порт для клиента mysqlpid_file = /path/to/pid # путь к pid-файлуbinlog_path = /path/to/binlog # путь к binary logmax_matches = 1000 # количество результатовworkers = threads # обязательно для real-time

}

13 / 32

Page 14: Sphinx — универсальное средство поиска

Минимальная конфигурацияНастроить пути можно единообразно с помощью PHP:

#!/usr/bin/php<?php function p($p) { echo __DIR__."/$p\n"; } ?>index entity{

type = rtpath = <?php p("var") ?>...

Дальше можно экспериментировать:

$ searchd -c sphinx.conf$ mysql --port=9306 --host=127.0.0.1

14 / 32

Page 15: Sphinx — универсальное средство поиска

Изменение индексаINSERT INTO test (id, title, categories, attributes)

VALUES(1, ’First document’, (5,10,20),’{ "attr1": 100, "ids": [10,20,30] }’);

DELETE FROM test WHERE id=1;DELETE FROM test WHERE id > 1000;TRUNCATE test;

-- Полное изменение (необходимо для полей, JSON и string):REPLACE INTO test (id, title, categories, attributes)

VALUES(1, ’First document title’, (5,15),’{ "attr2": 200, "ids": [10,20] }’);

-- Изменение по месту (для чисел, включая MVA):UPDATE test SET categories = (10,20) WHERE id=1;-- Также для числовых атрибутов JSON:UPDATE test SET attributes.attr1=200 WHERE id=1;

-- Добавление атрибутов (только int,bigint,float,bool):ALTER TABLE test ADD COLUMN git INTEGER;

15 / 32

Page 16: Sphinx — универсальное средство поиска

SELECT• все вычисляемые выражения должны быть поименованы всписке колонок

• FROM — список индексов для поиска, а не JOIN• WHERE — один MATCH() для полнотекстового поиска,остальное — фильтры

• GROUP BY — возможна группировка по несколькимколонкам и вычисляемым выражениям

• ORDER BY — только по колонкам, вычисляемые выраженияпо имени колонки

• по умолчанию применяется LIMIT• OPTION — дополнительные опции выполнения запроса

16 / 32

Page 17: Sphinx — универсальное средство поиска

WITHIN GROUP ORDER BY> SELECT * FROM product ORDER BY category ASC LIMIT 3;+------+----------+-------+---------+-------------+-----------+| id | category | price | title | tags | published |+------+----------+-------+---------+-------------+-----------+| 5 | 1 | 95 | Item 6 | 39,98,382 | 1 || 20 | 1 | 72 | Item 21 | 101,393,410 | 0 || 23 | 1 | 61 | Item 24 | 2,42,84 | 1 |+------+----------+-------+---------+-------------+-----------+

> SELECT * FROM product WHERE published=1 GROUP BY categoryORDER BY category ASC LIMIT 3;

+------+----------+-------+----------+------------+-----------+| id | category | price | title | tags | published |+------+----------+-------+----------+------------+-----------+| 5 | 1 | 95 | Item 6 | 39,98,382 | 1 || 158 | 2 | 45 | Item 159 | 71,246,290 | 1 || 50 | 3 | 99 | Item 51 | 30,157,500 | 1 |+------+----------+-------+----------+------------+-----------+

> SELECT * FROM product WHERE published=1GROUP BY category WITHIN GROUP ORDER BY PRICE DESC ORDER BY categoryASC LIMIT 3;

+------+----------+-------+-----------+-------------+-----------+| id | category | price | title | tags | published |+------+----------+-------+-----------+-------------+-----------+| 3841 | 1 | 100 | Item 3842 | 149,367,418 | 1 || 1112 | 2 | 100 | Item 1113 | 58,286,375 | 1 || 360 | 3 | 100 | Item 361 | 252,350,439 | 1 |+------+----------+-------+-----------+-------------+-----------+

17 / 32

Page 18: Sphinx — универсальное средство поиска

GROUP {N} BY

> SELECT * FROM product WHERE published=1GROUP 3 BY categoryWITHIN GROUP ORDER BY PRICE DESCORDER BY category ASCLIMIT 12;

+------+----------+-------+-----------+-------------+-----------+| id | category | price | title | tags | published |+------+----------+-------+-----------+-------------+-----------+| 3841 | 1 | 100 | Item 3842 | 149,367,418 | 1 || 8827 | 1 | 100 | Item 8828 | 12,272,476 | 1 || 1735 | 1 | 99 | Item 1736 | 121,220,461 | 1 || 1112 | 2 | 100 | Item 1113 | 58,286,375 | 1 || 1306 | 2 | 99 | Item 1307 | 336,371,388 | 1 || 2173 | 2 | 98 | Item 2174 | 99,187,203 | 1 || 360 | 3 | 100 | Item 361 | 252,350,439 | 1 || 1480 | 3 | 100 | Item 1481 | 54,308,363 | 1 || 8214 | 3 | 100 | Item 8215 | 179,482,495 | 1 || 558 | 4 | 99 | Item 559 | 118,133,432 | 1 || 760 | 4 | 99 | Item 761 | 113,124,458 | 1 || 6849 | 4 | 99 | Item 6850 | 158,267,469 | 1 |+------+----------+-------+-----------+-------------+-----------+

18 / 32

Page 19: Sphinx — универсальное средство поиска

INTERVAL

> SELECT id, price,INTERVAL(price, 0,21,41,61,81,101) prange, count(*) numFROM productWHERE published=1GROUP BY prange WITHIN GROUP ORDER BY price DESCORDER BY prange ASC;

+------+-------+--------+------+| id | price | prange | num |+------+-------+--------+------+| 146 | 20 | 1 | 1065 || 134 | 40 | 2 | 1020 || 713 | 60 | 3 | 1026 || 55 | 80 | 4 | 970 || 360 | 100 | 5 | 947 |+------+-------+--------+------+

19 / 32

Page 20: Sphinx — универсальное средство поиска

GROUP BY MVA> SELECT id, title, tags FROM product LIMIT 4;+------+--------+-------------+| id | title | tags |+------+--------+-------------+| 1 | Item 2 | 150,387,449 || 2 | Item 3 | 72,139,239 || 3 | Item 4 | 95,199,261 || 4 | Item 5 | 179,288,467 |+------+--------+-------------+

> SELECT id, title, GROUPBY() tag, COUNT(*) numFROM productGROUP BY tagsWITHIN GROUP ORDER BY price DESCLIMIT 4;

+------+----------+------+------+| id | title | tag | num |+------+----------+------+------+| 13 | Item 14 | 266 | 71 || 30 | Item 31 | 64 | 61 || 50 | Item 51 | 157 | 50 || 101 | Item 102 | 385 | 55 |+------+----------+------+------+

20 / 32

Page 21: Sphinx — универсальное средство поиска

JSON-атрибуты• поддерживаются с версии 2.1• filter, sort, group• массивы: LENGTH(), LEAST(), GREATEST()• поиск по JSON: ANY(), ALL(), INDEXOF()

{"category": 10,"title": "test","tags": [ 10, 20, 30 ],"attrs": [

{ "name": "attr1", "value": 500 },...

]}

21 / 32

Page 22: Sphinx — универсальное средство поиска

JSON: ANY, ALL, INDEXOF

[ANY|ALL|INDEXOF] (cond FOR var IN json.array)

ANY хотя бы один элемент удовлетворяет условиюALL все элементы удовлетворяют условию

INDEXOF индекс первого элемента, удовлетворяющегоусловию

SELECT *, ANY (item.name = "attr1" AND item.value = 500FOR item IN json.attrs

) as condFROM index WHERE cond = 1;

22 / 32

Page 23: Sphinx — универсальное средство поиска

JSON: плюсы и минусыСуперфича: возможность организации индекса с

произвольной структурой, например, поддержкапроизвольного набора атрибутов товара.

Проблемы:

• существенное потребление памяти• отсутствие (пока) поддержки GROUPBY() дляэлементов-массивов (поддержка просто GROUP BY — есть.

Контролируем использование памяти, не пытаемся превратитьв документ-ориентированную базу, это все же индекс.

23 / 32

Page 24: Sphinx — универсальное средство поиска

EAV-поискВ базе реализован EAV, нужно обеспечить поиск по значениямсвойств:

• создаем JSON-атрибут для значений свойств• используем линейную структуру { "attrId": valueId }• стараемся максимально использовать справочникизначений для минимизации значений индекса, строковыезначения в JSON — накладно

• изменение набора свойств автоматически учитывается приочередном переиндексировании

• отсутствующие в атрибуте свойства просто игнорируютсяпри поиске

24 / 32

Page 25: Sphinx — универсальное средство поиска

EAV-поиск: пример

> SELECT * FROM product LIMIT 1\G*************************** 1. row ***************************

id: 1price: 596title: Item 2categories: 3,17,20attrs: {"a22":1847,"a39":1369,"a147":383,"a74":1341,"a14":1877,

"a38":1992,"a50":550, "a100":630,"a10":1533,"a118":615}

> SELECT id, title FROM PRODUCT WHERE categories=10 AND attrs.a61=1068;+-------+------------+| id | title |+-------+------------+| 11100 | Item 11101 || 34807 | Item 34808 |+-------+------------+

25 / 32

Page 26: Sphinx — универсальное средство поиска

Фасетный поиск• категория 1 (30)• категория 2 (64)• категория 3 (52)

КатегорииMVA-атрибут categories, документпринадлежит нескольким категориям

• значение 1 (27)• значение 2 (32)• значение 3 (60)

Свойство 1Элемент attrs.a1 JSON-атрибута attrs,документу соответствует идентификаторзначение, само значение в справочнике

• значение 4 (12)• значение 5 (44)• значение 6 (13)

Свойство 2Элемент attrs.a2 JSON-атрибута attrs,аналогично.

Основной принцип — набор запросов с одинаковым WHERE(значения, выбранные пользователем), но разным GROUP BY.

26 / 32

Page 27: Sphinx — универсальное средство поиска

Фасетный поиск> SELECT * FROM product LIMIT 2;+------+-------+--------+------------+----------------------------------+| id | price | title | categories | attrs |+------+-------+--------+------------+----------------------------------+| 1 | 570 | Item 2 | 10,12,20 | {"a5":11,"a4":8,"a3":5,"a6":6} || 2 | 131 | Item 3 | 5,18 | {"a5":2,"a4":13,"a2":18,"a6":27} |+------+-------+--------+------------+----------------------------------+

> SELECT GROUPBY() c, COUNT(*) n FROM productWHERE categories IN (1,2,7) AND attrs.a1 IN (3,5,10) AND attrs.a2 IN (1,2,20)GROUP BY categories HAVING c IN (1,2,7);

+------+------+| c | n |+------+------+| 1 | 126 || 7 | 160 || 2 | 152 |+------+------+

> SELECT attrs.a1 v, COUNT(*) n FROM productWHERE categories IN (1,2,7) AND attrs.a1 IN (3,5,10) AND attrs.a2 IN (1,2,20)GROUP BY attrs.a1;

+----------+------+| v | n |+----------+------+| 3 | 3 || 5 | 1 || 10 | 1 |+----------+------+

27 / 32

Page 28: Sphinx — универсальное средство поиска

Multi-query OptimizationФасетный поиск — набор запросов с одинаковым WHERE,отличия только в группировке и сортировке→ можноприменить фильтр только один раз.

Выполняем запросы в режиме multiquery — несколькозапросов через ; за одно обращение к серверу.

SELECT attrs.a1 v, COUNT(*) n FROM productWHERE categories IN (1,2,7)

AND attrs.a1 IN (3,5,10) AND attrs.a2 IN (1,2,20)GROUP BY attrs.a1;SELECT attrs.a2 v, COUNT(*) n FROM productWHERE categories IN (1,2,7)

AND attrs.a1 IN (3,5,10) AND attrs.a2 IN (1,2,20)GROUP BY attrs.a2;...

28 / 32

Page 29: Sphinx — универсальное средство поиска

Ограничения multi-queryНа данный момент:

• не выполняется для вычисляемых выражений• не выполняется для строковых атрибутов

Проверка выполнения оптимизации: xN, N — число совместновыполненных запросов, в query log.

[Sun Jul 12 15:18:17.000 2009] 0.040 sec x3 [ext/0/rel 747541 (0,20)] ...[Sun Jul 12 15:18:17.000 2009] 0.040 sec x3 [ext/0/ext 747541 (0,20)] ...[Sun Jul 12 15:18:17.000 2009] 0.040 sec x3 [ext/0/ext 747541 (0,20)] ...

29 / 32

Page 30: Sphinx — универсальное средство поиска

Эффективность поиска

Атрибуты позволяют строить сложные условия поиска, но этоfullscan по индексу — затратно.

Самый эффективный вариант:

• ограничиваем результат за счет полнотекстового поиска• применяем сложные фильтры уже к полученномурезультату

Если полнотекстового поиска нет, эффективность поотношению к MySQL зависит от ситуации.

30 / 32

Page 31: Sphinx — универсальное средство поиска

Диагностика> SHOW META+---------------+-------+| Variable_name | Value |+---------------+-------+| total | 3 || total_found | 3 || time | 0.002 |+---------------+-------+

> SHOW INDEX product STATUS+-------------------+---------+| Variable_name | Value |+-------------------+---------+| index_type | rt || indexed_documents | 49999 || indexed_bytes | 0 || ram_bytes | 5323677 || disk_bytes | 4872172 |+-------------------+---------+

> SHOW STATUS+--------------------+-------+| Counter | Value |+--------------------+-------+| uptime | 22 || connections | 1 || maxed_out | 0 || command_search | 2 || command_excerpt | 0 || command_update | 0 || command_delete | 0 || command_keywords | 0 |

...| avg_query_cpu | OFF || avg_dist_wall | 0.000 || avg_dist_local | 0.000 || avg_dist_wait | 0.000 || avg_query_reads | OFF || avg_query_readkb | OFF || avg_query_readtime | OFF |+--------------------+-------+

31 / 32

Page 32: Sphinx — универсальное средство поиска

Что читать• Sphinx 2.1.4-release reference manual1

• Real time fulltext search with Sphinx2

• Fulltext engine for non fulltext searches3

• Sphinx search performance optimization: attribute-basedfilters4

• Full JSON Support in Trunk5

• Sphinx Faceting Example6

1http://sphinxsearch.com/docs/2.1.4/2http://slidesha.re/1gj1nS33http://slidesha.re/19D0y1n4bit.ly/1cTcJNI5http://sphinxsearch.com/blog/2013/08/08/full-json-support-in-trunk/6https://github.com/adriannuta/SphinxFacetingExample

32 / 32