Last active
January 17, 2025 02:23
-
-
Save codedokode/10539366 to your computer and use it in GitHub Desktop.
Revisions
-
codedokode revised this gist
Oct 3, 2015 . 1 changed file with 4 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,8 +1,10 @@ <?php error_reporting(-1); // номер порта берется из конфига сфикса а не наугад // Если вместо 127.0.0.1 написать localhost, то под линуксом PDO может приконнектиться к MySQL // вместо сфинкса через юникс-сокет, игнорируя указанный номер порта (MySQL использует // порт 3306 в отличие от сфинкса) // Мануал: http://php.net/manual/ru/ref.pdo-mysql.connection.php#refsect1-ref.pdo-mysql.connection-notes $pdo = new PDO('mysql:host=127.0.0.1;port=9306'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); -
codedokode revised this gist
Oct 3, 2015 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,9 @@ <?php error_reporting(-1); // номер порта берется из конфига сфикса а не наугад // Если вместо 127.0.0.1 написать localhost, то под линуксом PDO может приконнектиться к MySQL через юникс-сокет, // игнорируя указанный номер порта (MySQL исплоьзует порт 3306 в отличие от сфинкса) $pdo = new PDO('mysql:host=127.0.0.1;port=9306'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Ищем слово «курс» в индексе новостей -
codedokode renamed this gist
Apr 12, 2014 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
codedokode revised this gist
Apr 12, 2014 . 3 changed files with 106 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,15 @@ <?php error_reporting(-1); require __DIR__.'/api/sphinxapi.php'; $client = new SphinxClient(); // данные берем из конфига $client->SetServer('localhost', 9312); $client->SetConnectTimeout(1); $client->SetArrayResult(true); $result = $client->Query("черный"); var_dump($result); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,79 @@ # Источник данных — MySQL # В конфиге источники могут наследоваться. создадим базовый конфиг для любых MySQL-источников # чтобы не копипастить данные для подключения source base { type = mysql sql_host = localhost sql_user = tester sql_pass = password sql_db = tester sql_port = 3306 # Ставим кодировку при соединении sql_query_pre = SET NAMES utf8 } # Теперь настроим источник данных для выборки новостей наследующийся от базового source src_news: base { # Включаем range (выборку больших таблиц по частям) sql_range_step = 1000 # запрос на выборку диапазона id sql_query_range = SELECT MIN(id), MAX(id) FROM news # запрос на выборку самих новостей для индексации # сфинкс понимает даты только в виде числа, так что преобразуем дату в timestamp sql_query = \ SELECT id, topic, header, body, UNIX_TIMESTAMP(added) AS added \ FROM news WHERE id BETWEEN $start AND $end # Сохраняем для каждой новости ее topic и дату в аттрибуты sql_attr_uint = topic sql_attr_timestamp = added } # Теперь создаем индекс из данных взятых из источника index index_news { source = src_news # где хранить данные # не знаю, как писать относительный путь, потому пишу абсолютный path = d:/temp/s/data/news # где хранить аттрибуты — в индексе (inline) или отдельном файле (extern) docinfo = extern # Либо sbcs (1-байтовая кодировка) либо utf-8 charset_type = utf-8 } # Говорим сколько памяти можно использовать при индексации (если недодать то будет ошибка) # объем памяти зависит от размера таблицы и опредеояется опытным путем indexer { mem_limit = 20M } # настройки поискового демона searchd { # на каких портах слушать с бинарным проткоолом listen = 9312 # и с mysql-протоколом listen = 9306:mysql41 # Куда класть логи log = d:/temp/s/log/searchd.log query_log = d:/temp/s/log/query.log read_timeout = 5 max_children = 30 pid_file = d:/temp/s/log/searchd.pid max_matches = 1000 seamless_rotate = 1 preopen_indexes = 1 unlink_old = 1 workers = threads # for RT to work binlog_path = d:/temp/s/data } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,12 @@ <?php error_reporting(-1); // номер порта берется из конфига сфикса а не наугад $pdo = new PDO('mysql:host=localhost;port=9306'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Ищем слово «курс» в индексе новостей // мануал: http://sphinxsearch.com/docs/manual-2.2.1.html#sphinxql-select $stmt = $pdo->query("SELECT * FROM index_news WHERE MATCH('курс')"); $results = $stmt->fetchAll(); var_dump($results); -
codedokode created this gist
Apr 12, 2014 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,179 @@ # Как установить и настроить сфинкс. Скачиваем сфинкс (берем версию с MySQL и со стеммингом на 15 языков Win32 binaries w/MySQL+PgSQL+libstemmer+id64 support соответствующую битности твоей ОС), распаковываем например в d:\temp\s\ На этом установка sphinx завершена. В дебиане просто делаем `sudo apt-get install sphinxsearch`. Создаем таблицы: CREATE TABLE news (id INT(10) AUTO_INCREMENT PRIMARY KEY, topic INT(10) NOT NULL, header VARCHAR(200) NOT NULL, body TEXT, added TIMESTAMP DEFAULT CURRENT_TIMESTAMP); Вбиваем данные: INSERT INTO news (topic, header, body) VALUES (1, 'Биржевой курс евро приблизился к 46 рублям', 'Курс евро во второй половине торгов на Московской бирже 21 января приблизился к 46 рублям. К 17:00 по московскому времени европейская валюта подорожала почти на 18 копеек до 45,9795 рубля. Курс доллара к тому же времени вырос на 21 копейку до 33,98 рубля.'), (1, 'Найденный в ЮАР алмаз оценили в 15 миллионов долларов', 'В Южной Африке нашли голубой алмаз, который предварительно оценен в 15-20 миллионов долларов. За эту сумму, по мнению экспертов, камень может быть продан на аукционе, сообщает Reuters.'), (2, 'В Петербурге исчез музей-квартира Ленина', 'Партия «Коммунисты России» потребовала, чтобы власти Санкт-Петербурга восстановили музей, действовавший в последней конспиративной квартире Владимира Ленина. Об этом 21 января сообщается на сайте партии.'), (1, 'Hello world', 'Test news for search'); Пишем конфиг для индексера например в d:\temp\s\sphinx.conf на основе sphinx-min.conf.in, мануала и интуиции (файл `sphinx.conf`, приложен ниже). В конфиге упомняуты папки log и data, так что созадем их в d:\temp\s\ Аттрибуты (`added` и `topic`) — это числа, которые можно сохранить в поисковый индекс и потом использовать их в условии поиска (для поиска в определенной теме или сортировки по дате). Уф. Тяжело потрудились. Попробуем теперь запустить индексер, открываем консоль (гайд по использованию консоли https://gist.github.com/codedokode/586dabb540415e0cc3d3 ), переходим в папку сфинкса и печатаем: .\bin\indexer --config sphinx.conf --all (под линуксом печатаем просто indexer так как там он прописан в системную папку). Если все ОК, выведется текст, и там мы увидим: > indexing index 'index_news'... > > WARNING: collect_hits: mem_limit=20480 kb too low, increasing to 25856 kb Мало памяти, надо минимум 25 Мб (и зачем ему столько?) > total 4 docs, 1418 bytes > > total 0.030 sec, 45854 bytes/sec, 129.34 docs/sec 4 документа из базы проиндексировались Ок, индекс создан в папочке data, проверим, работает ли поиск? Набираем .\bin\search --config sphinx.conf "курс" Вот так печалька, ничего не найдено. Еще бы, виндовая консоль не умеет в utf-8 и коверкает наши буковки. Попробуем английский: .\bin\search --config sphinx.conf "hello" Сфинкс вернул нам id новости, отлично. Теперь запустим поисковый демон и перейдем к PHP (и к поддержке utf-8). Запускаем демон: .\bin\searchd --config sphinx.conf --console (`--console` чтобы он не пытался уйти в фоновый режим и его можно было остановить через `Ctrl + C`). Появятся надписи что все хорошо. Из PHP к сфинксу можно подсоединиться 2 способами: - через mysql-совместимый протокол подсоединиться к демону как к БД и искать с помощью SQL-запросов - использовать sphinx.api.php и бинарный протокол Начнем с варианта 1. Пишем `test-sql.php` (код в приложении). Запускаем его, из консоли или через браузер и сервер (демон поиска должен быть запущен естественно). Если все верно, в ответ вернется массив вроде такого, с id документа и его аттрибутами: array(1) { [0] => array(6) { 'id' => string(1) "1" [0] => string(1) "1" 'topic' => string(1) "1" [1] => string(1) "1" 'added' => string(10) "1390318498" [2] => string(10) "1390318498" } } Перейдем к sphinx.api.php (мануал по апи: http://sphinxsearch.com/docs/manual-2.2.1.html#api-reference ). Берем пример кода из папки api и пишем на его основе код `api-test.php` (приложен ниже). Запускаем, тоже видим массив с результатами. Хорошо, когда все работает. ### Стемминг Если мы сейчас попробуем поискать слово с учетом склонения, например «курсом» то ничего не найдем, так как в тексте нет таких слов. Нехорошо. Давай исправлять это при помощи встроенных возможностей сфинкса. В сфинксе есть такие возможности преобразования слов при индексировании: lemmatizer (приводит слово в нормальную форму: running -> run), stemmer (отрезает окончания слов, не особо заботясь о логике, business -> busi но зато простой и не требует словаря), фонетические алгоритмы (soundex, metaphone заменяют похожие звуки в слове для поиска с неправильным написанием слова но только в английских словах). Мануал: http://sphinxsearch.com/docs/manual-2.2.1.html#conf-morphology Подключим русский и англ. стеммер, прописав в конфиге в секции index_news: morphology = stem_ru, stem_en Индекс сам себя не обновит, так что останавливаем демон (Ctrl + C), запускаем переиндексацию и перезапускаем демон (когда демон работает в фоновом режиме, можно дописать ключ `--rotate` и индексер сам попросит демона перезагрузить индексы, при этом работа поиска не прервется): .\bin\indexer --config sphinx.conf --all Теперь попробуем поискать по слову «курса» через PHP-скрипт. Все должно работать. Лемматайзер конечно работает качественнее, так что лучше скачать нужные словари и подключить его. ### Другие возможности Сфинкс умеет еще вырезать HTML-теги и декодировать HTML-сущности (параметр `html_strip`), задавать диапазон символов (`charset_table`), исключения и синонимы (`wordforms` и `exceptions`). Можно задать, какие символы являются и не являются частью слова (например чтобы слова разделенные подчеркиванием считались как разные). Также, сфинкс может строить сниппеты в результатах поиска (вырезать куски текста рядом с подсвеченным ключевым словом), с помощью функции `BuildExcerpts()` в API. ### Autocomplete Sphinx можно использовать для реализации автокомплита в поиске. т.е. дополнения по началу слова а также исправления опечаток (мануал http://sphinxsearch.com/blog/2013/05/21/simple-autocomplete-and-correction-suggestion/ ). ### Realtime-индексы Ок, у нас есть индекс для поиска. Но как обновлять его при добавлении новых данных или удалении старых? Ну с удалением просто, если sphinx вернул нам id несуществующей в таблице записи — значит, она удалена. А как добавлять данные в индекс? Для этого используются realtime-индексы. Rt индексы можно обновлять с задержкой в несколько миллисекунд (по крайней мере так говорят авторы), но они не очень эффективно хранят данные и много данных в них лучше не помещать. То, есть мы делаем так: - основной индекс, содержит все записи (или все записи старше определенной даты), полностью перестраивается раз в час/в сутки в заивисимости от объема данных - RT-индекс, который хранит только новые данные, которых нет в основном индексе, который обновляется в реальном времени и который очищается при переиндексации Добавим RT-индекс в конфиг: index rt_news { type = rt path = d:/temp/s/data/rt_news # Надо описывать все возможные поля для индексирования rt_field = header rt_field = body rt_attr_uint = added rt_attr_uint = topic # Сколько памяти отведем под индекс (что не поместится, будет храниться на диске) rt_mem_limit = 25M } Ок, теперь перезапускаем индексер и демон. Добавление в Rt-индекс делается SQL-запросами, так что возьмем sql-test.php и чуть-чуть переделаем: $st = $pdo->prepare("INSERT INTO rt_news (id, topic, header, body, added) VALUES (?, ?, ?, ?, ?)"); $st->execute(array(100, 1, 'Проверим realtime index', 'Это текст проверки rt индекса', time())); Запустим наш файл. Теперь поиском убедимся, что поиск по слову «проверим» и «realtime» выдает нам результаты. Если ты ищешь через SQL, а не через api, не забудь указать в запросе оба индекса (`SELECT ( FROM index_news, rt_news ...` )). Индекс можно обновить через вставку новой записи с таким же id помощью REPLACE, проверим: $st = $pdo->prepare("REPLACE INTO rt_news (id, topic, header, body, added) VALUES (?, ?, ?, ?, ?)"); $st->execute(array(100, 1, 'Черный кот в черном доме', 'здесь ничего нет', time())); Убедимся, что теперь ищется слово кот, а по слову realtime резальтотов нет. Ну и можно еще удалять записи из RT-индекса, с помощью `DELETE FROM rt_news WHERE id IN(1, 2, 3)` ### Поисковые запросы Sphinx понимает хитрый синтаксис в поисковых запросах ( http://sphinxsearch.com/docs/manual-2.2.1.html#searching ): - оператор ИЛИ: `слово1 | слово2` - оператор НЕ: `слово1 -слово2` - скобки для группировки - и мнгого других опций, которые есть в мануале Можно сортировать и группировать результаты по разным аттрибутам. ### Доплнительное чтение Вот неплохая статья на русском про то, как sphinx обрабатывает слова в тексте и некоторые настройки для этого: http://chakrygin.ru/2013/07/sphinx-search.html