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

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

Nov 15, 2014

Download

Technology

Очередной семинар был посвящен средствам фильтрации результатов поиска поискового сервера Sphinx. Были рассмотрены методы отладки поисковых поисковых запросов, особенности языка SphinxQL, варианты фильтрации произвольного набора атрибутов в схеме EAV и реализация фасетного поиска.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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