[Из песочницы] Поиск в Mediawiki при помощи Sphinx
Здравствуй, читатель! Некоторое время назад мне была поставлена задача внедрения MediaWiki в корпоративной сети.И главной проблемой этого внедрения стал поиск информации, содержащейся в вики.В этой статье я хотел бы рассказать о том, как подружить поиск Sphinx с MediaWiki.Причина по которой я хотел бы это написать — отсутствие русскоязычной документации и более-менее приличного руководства или описания, которое помогало бы моим коллегам быстро и просто начать использовать этот прекрасный поисковый механизм.Возможно, я просто не умею пользоваться гуглом…
Зачем это нужноЦель данного внедрения в нашей организации — перенос корпоративной базы знаний в более удобный формат представления и исправления\добавления.Руководство видело только сплошные плюсы, а мои доводы о минусах никто и слушать не хотел.Ведь так здорово видеть в УК холдинга работающую вики и так не хочется думать о том, какие проблемы при работе с этой самой вики.К слову сказать — компания наша реализует проекты по автоматизации документооборота в комплексе.Заказчики крупные, решения сложные и порой нестандартные.И статьи в вики предполагается иметь не только о проектах, но и о технических решениях, фичах и т.п., инновационных методах и технологиях.А также в планах использовать ее как источник информации для новых сотрудников- им предстоит изучить достаточно приличный объем информации и удобство доступа к ней в настоящий момент оставляет желать лучшего.
Как было сказано выше — за основу был взят популярный движок MediaWiki. А ключевой проблемой, которую я предсказывал еще в самом начале, стала проблема поиска информации.Всем известно — стандартный поиск совсем плох. И закономерным стал вопрос — как исправить это недоразумение.
Подготовка
Итак, все развернуто на Windows Server 2012 R2 64bit, естественно поднят IIS: 
Самые последние версии на момент установки. Расширение SphinxSearch на скрине уже подключено. Как это сделать я напишу чуть ниже.
Необходимо скачать сам поисковый движок с официального сайта. Я выбрал 2.1.9-release (July 2014).Также необходимо скачать расширение для MediaWiki.Его я брал на GIT WikiMediaВерсия 0.9.0 была актуальной.
Установка и настройка поискового движка Sphinx После скачивания движка я распаковал его в C:\inetpub\wwwroot\mw\sphinx).Следующий шаг — подготовка конфига. В качестве основы я взял файл sphinx.conf.inУ меня получился вот такой рабочий, который я и привожу тут с комментариями. # data source definition for the main index source src_wiki_main { type = mysql # data source sql_host= 127.0.0.1 # localhost не работает в силу специфики Win7+ ветки sql_user= mwuser sql_pass= sql_db= sql_port= 3306# optional, default is 3306 # pre-query, executed before the main fetch query. Дабы понималась кодировка в базе sql_query_pre= SET NAMES utf8 # main document fetch query — change the table names if you are using a prefix # Этот и последующий запросы предоставлены самим разработчиком расширения. sql_query= SELECT page_id, page_title, page_namespace, page_is_redirect, old_id, old_text FROM page, revision, text WHERE rev_id=page_latest AND old_id=rev_text_id # attribute columns sql_attr_uint= page_namespace sql_attr_uint= page_is_redirect sql_attr_uint= old_id # collect all category ids for category filtering sql_attr_multi = uint category from query; SELECT cl_from, page_id AS category FROM categorylinks, page WHERE page_title=cl_to AND page_namespace=14 # used by command-line search utility to display document information sql_query_info= SELECT page_title, page_namespace FROM page WHERE page_id=$id } # data source definition for the incremental index source src_wiki_incremental: src_wiki_main { # adjust this query based on the time you run the full index # in this case, full index runs at 7 AM UTC sql_query= SELECT page_id, page_title, page_namespace, page_is_redirect, old_id, old_text FROM page, revision, text WHERE rev_id=page_latest AND old_id=rev_text_id AND page_touched>=DATE_FORMAT (CURDATE (), '%Y%m%d070000') # Тип поиска должен быть plain type = plain } # main index definition index wiki_main { type = plain # which document source to index source= src_wiki_main # this is path and index file name without extension # you may need to change this path or create this folder path= C:/inetpub/wwwroot/mw/sphinx/data/wiki_main # docinfo (ie. per-document attribute values) storage strategy docinfo= extern # morphology morphology= stem_en, stem_ru # stopwords file #stopwords= /var/data/sphinx/stopwords.txt # minimum word length min_word_len= 1 # allow wildcard (*) searches min_infix_len = 1 enable_star = 1 # charset encoding type charset_type= utf-8 # charset definition and case folding rules «table» # Это позволяет включать поиск по русскоязычным источникам. По умолчанию он не работает без этой магии. charset_table= 0…9, A…Z→a…z, a…z, \ U+C0→a, U+C1→a, U+C2→a, U+C3→a, U+C4→a, U+C5→a, U+C6→a, \ U+C7→c, U+E7→c, U+C8→e, U+C9→e, U+CA→e, U+CB→e, U+CC→i, \ U+CD→i, U+CE→i, U+CF→i, U+D0→d, U+D1→n, U+D2→o, U+D3→o, \ U+D4→o, U+D5→o, U+D6→o, U+D8→o, U+D9→u, U+DA→u, U+DB→u, \ U+DC→u, U+DD→y, U+DE→t, U+DF→s, \ U+E0→a, U+E1→a, U+E2→a, U+E3→a, U+E4→a, U+E5→a, U+E6→a, \ U+E7→c, U+E7→c, U+E8→e, U+E9→e, U+EA→e, U+EB→e, U+EC→i, \ U+ED→i, U+EE→i, U+EF→i, U+F0→d, U+F1→n, U+F2→o, U+F3→o, \ U+F4→o, U+F5→o, U+F6→o, U+F8→o, U+F9→u, U+FA→u, U+FB→u, \ U+FC→u, U+FD→y, U+FE→t, U+FF→s, U+410…U+42F→U+430…U+44F, \ U+430…U+44F, U+0400→U+0435, U+0401→U+0435, U+0402→U+0452, \ U+0452, U+0403→U+0433, U+0404→U+0454, U+0454, U+0405→U+0455, \ U+0455, U+0406→U+0456, U+0407→U+0456, U+0457→U+0456, U+0456, \ U+0408…U+040B→U+0458…U+045B, U+0458…U+045B, U+040C→U+043A, \ U+040D→U+0438, U+040E→U+0443, U+040F→U+045F, U+045F, \ U+0450→U+0435, U+0451→U+0435, U+0453→U+0433, U+045C→U+043A, \ U+045D→U+0438, U+045E→U+0443, U+0460→U+0461, U+0461, U+0462→U+0463, \ U+0463, U+0464→U+0465, U+0465, U+0466→U+0467, U+0467, U+0468→U+0469, \ U+0469, U+046A→U+046B, U+046B, U+046C→U+046D, U+046D, U+046E→U+046F, \ U+046F, U+0470→U+0471, U+0471, U+0472→U+0473, U+0473, U+0474→U+0475, \ U+0476→U+0475, U+0477→U+0475, U+0475, U+0478→U+0479, U+0479, \ U+047A→U+047B, U+047B, U+047C→U+047D, U+047D, U+047E→U+047F, U+047F, \ U+0480→U+0481, U+0481, U+048A→U+0438, U+048B→U+0438, U+048C→U+044C, \ U+048D→U+044C, U+048E→U+0440, U+048F→U+0440, U+0490→U+0433, \ U+0491→U+0433, U+0490→U+0433, U+0491→U+0433, U+0492→U+0433, \ U+0493→U+0433, U+0494→U+0433, U+0495→U+0433, U+0496→U+0436, \ U+0497→U+0436, U+0498→U+0437, U+0499→U+0437, U+049A→U+043A, \ U+049B→U+043A, U+049C→U+043A, U+049D→U+043A, U+049E→U+043A, \ U+049F→U+043A, U+04A0→U+043A, U+04A1→U+043A, U+04A2→U+043D, \ U+04A3→U+043D, U+04A4→U+043D, U+04A5→U+043D, U+04A6→U+043F, \ U+04A7→U+043F, U+04A8→U+04A9, U+04A9, U+04AA→U+0441, U+04AB→U+0441, \ U+04AC→U+0442, U+04AD→U+0442, U+04AE→U+0443, U+04AF→U+0443, U+04B0→U+0443, \ U+04B1→U+0443, U+04B2→U+0445, U+04B3→U+0445, U+04B4→U+04B5, U+04B5, \ U+04B6→U+0447, U+04B7→U+0447, U+04B8→U+0447, U+04B9→U+0447, U+04BA→U+04BB, \ U+04BB, U+04BC→U+04BD, U+04BE→U+04BD, U+04BF→U+04BD, U+04BD, U+04C0→U+04CF, \ U+04CF, U+04C1→U+0436, U+04C2→U+0436, U+04C3→U+043A, U+04C4→U+043A, \ U+04C5→U+043B, U+04C6→U+043B, U+04C7→U+043D, U+04C8→U+043D, U+04C9→U+043D, \ U+04CA→U+043D, U+04CB→U+0447, U+04CC→U+0447, U+04CD→U+043C, U+04CE→U+043C, \ U+04D0→U+0430, U+04D1→U+0430, U+04D2→U+0430, U+04D3→U+0430, U+04D4→U+00E6, \ U+04D5→U+00E6, U+04D6→U+0435, U+04D7→U+0435, U+04D8→U+04D9, U+04DA→U+04D9, \ U+04DB→U+04D9, U+04D9, U+04DC→U+0436, U+04DD→U+0436, U+04DE→U+0437, \ U+04DF→U+0437, U+04E0→U+04E1, U+04E1, U+04E2→U+0438, U+04E3→U+0438, \ U+04E4→U+0438, U+04E5→U+0438, U+04E6→U+043E, U+04E7→U+043E, U+04E8→U+043E, \ U+04E9→U+043E, U+04EA→U+043E, U+04EB→U+043E, U+04EC→U+044D, U+04ED→U+044D, \ U+04EE→U+0443, U+04EF→U+0443, U+04F0→U+0443, U+04F1→U+0443, U+04F2→U+0443, \ U+04F3→U+0443, U+04F4→U+0447, U+04F5→U+0447, U+04F6→U+0433, U+04F7→U+0433, \ U+04F8→U+044B, U+04F9→U+044B, U+04FA→U+0433, U+04FB→U+0433, U+04FC→U+0445, \ U+04FD→U+0445, U+04FE→U+0445, U+04FF→U+0445, U+0410…U+0418→U+0430…U+0438, \ U+0419→U+0438, U+0430…U+0438, U+041A…U+042F→U+043A…U+044F, U+043A…U+044F, } # incremental index definition index wiki_incremental: wiki_main { type = plain path= C:/inetpub/wwwroot/mw/sphinx/data/wiki_incremental } # indexer settings indexer { # memory limit (default is 32M) mem_limit= 64M } # searchd settings searchd { # IP address and port on which search daemon will bind and accept listen= 127.0.0.1:9312 # searchd run info is logged here — create or change the folder log= C:/inetpub/wwwroot/mw/sphinx/log/searchd.log # all the search queries are logged here query_log= C:/inetpub/wwwroot/mw/sphinx/log/query.log # client read timeout, seconds read_timeout= 5 # maximum amount of children to fork max_children= 30 # a file which will contain searchd process ID pid_file= C:/inetpub/wwwroot/mw/sphinx/log/searchd.pid # maximum amount of matches this daemon would ever retrieve # from each index and serve to client max_matches= 1000 workers = threads } # --eof-- На этом конфигурирование сфинкса закончено.
Установка службы поиска Теперь установим нашу службу.Для этого в командной строке пишемC:/inetpub/wwwroot/mw/sphinx/bin/searchd --install --config C:/inetpub/wwwroot/mw/sphinx/bin/sphinx.conf --servicename SphinxSearchВсе должно пойти без ошибок и служба долна установиться и стать видимой через Администрирование — Службы под именем SphinxSearch.Пока ее запускать не стоит т.к. данные еще не проиндексированы и при запуске службы получим ошибку.Стоит отметить, что слэши используются именно такие /, а не такие \. В противном случае появится ошибка доступа к файлам логов и PID файлам процессов поискового движка.Также обращаю внимание, что conf файл лежит в папке с бинарниками (bin), дабы при запусках через консоль не писать пути к конфигу.Но при установке службы лучше написать по какому пути лежит конфиг.Теперь в командной строке переходим в папку с бинарниками (bin) и пишемindexer --allПолучаем результат вроде этого:
Sphinx 2.1.9-release (r4761) Copyright © 2001–2014, Andrew Aksyonoff Copyright © 2008–2014, Sphinx Technologies Inc (http://sphinxsearch.com) using config file './sphinx.conf'… indexing index 'wiki_main'… collected 159 docs, 0.5 MB collected 0 attr values sorted 0.0 Mvalues, 100.0% done sorted 1.6 Mhits, 100.0% done total 159 docs, 494176 bytes total 0.596 sec, 827807 bytes/sec, 266.34 docs/sec indexing index 'wiki_incremental'… collected 159 docs, 0.5 MB collected 0 attr values sorted 0.0 Mvalues, 100.0% done sorted 1.6 Mhits, 100.0% done total 159 docs, 494176 bytes total 0.584 sec, 844808 bytes/sec, 271.81 docs/sec total 4 reads, 0.005 sec, 2107.7 kb/call avg, 1.4 msec/call avg total 38 writes, 0.022 sec, 479.7 kb/call avg, 0.5 msec/call avg Все, индекс создан.Проверка работы поискового движка Как выяснилось выше — индекс создался. В командной строке мы все еще в папке с бинарниками. Теперь запускаем нашу службу SphinxSearch и в командной строке пишем что нибудь вроде: search wiki
У меня получился вот такой результат:
Sphinx 2.1.9-release (r4761) Copyright © 2001–2014, Andrew Aksyonoff Copyright © 2008–2014, Sphinx Technologies Inc (http://sphinxsearch.com) using config file './sphinx.conf'… index 'wiki_main': query 'wiki ': returned 13 matches of 13 total in 0.004 sec displaying matches: 1. document=76, weight=1719, page_namespace=0, page_is_redirect=0, old_id=929, c ategory=() page_title=???_CompanyNameWiki page_namespace=0 2. document=77, weight=1670, page_namespace=0, page_is_redirect=0, old_id=1136, category=() page_title=FAQ_CompanyNameWiki page_namespace=0 3. document=79, weight=1670, page_namespace=0, page_is_redirect=0, old_id=864, c ategory=() page_title=CompanyNameWiki:_??? page_namespace=0 4. document=81, weight=1670, page_namespace=12, page_is_redirect=0, old_id=939, category=() page_title=C???_???_??? page_namespace=12 5. document=128, weight=1670, page_namespace=0, page_is_redirect=0, old_id=1075, category=() page_title=??? page_namespace=0 6. document=1, weight=1648, page_namespace=0, page_is_redirect=0, old_id=1091, c ategory=() page_title=???_??? page_namespace=0 7. document=4, weight=1648, page_namespace=0, page_is_redirect=0, old_id=10, cat egory=() page_title=???_??? page_namespace=0 8. document=5, weight=1648, page_namespace=0, page_is_redirect=0, old_id=181, ca tegory=() page_title=???_???_???_(???_???) page_namespace=0 9. document=2, weight=1608, page_namespace=8, page_is_redirect=0, old_id=1135, c ategory=() page_title=Sidebar page_namespace=8 10. document=12, weight=1608, page_namespace=0, page_is_redirect=0, old_id=719, category=() page_title=???_CRM page_namespace=0 11. document=71, weight=1608, page_namespace=0, page_is_redirect=0, old_id=701, category=() page_title=???_??? page_namespace=0 12. document=80, weight=1608, page_namespace=12, page_is_redirect=0, old_id=862, category=() page_title=???_CompanyNameWiki page_namespace=12 13. document=129, weight=1608, page_namespace=0, page_is_redirect=0, old_id=1085 , category=() page_title=??? page_namespace=0 words: 1. 'wiki': 13 documents, 37 hits index 'wiki_incremental': query 'wiki ': returned 13 matches of 13 total in 0.00 0 sec displaying matches: 1. document=76, weight=1719, page_namespace=0, page_is_redirect=0, old_id=929, c ategory=() page_title=???_CompanyNameWiki page_namespace=0 2. document=77, weight=1670, page_namespace=0, page_is_redirect=0, old_id=1136, category=() page_title=FAQ_CompanyNameWiki page_namespace=0 3. document=79, weight=1670, page_namespace=0, page_is_redirect=0, old_id=864, c ategory=() page_title=CompanyNameWiki:_??? page_namespace=0 4. document=81, weight=1670, page_namespace=12, page_is_redirect=0, old_id=939, category=() page_title=C???_???_??? page_namespace=12 5. document=128, weight=1670, page_namespace=0, page_is_redirect=0, old_id=1075, category=() page_title=??? page_namespace=0 6. document=1, weight=1648, page_namespace=0, page_is_redirect=0, old_id=1091, c ategory=() page_title=???_??? page_namespace=0 7. document=4, weight=1648, page_namespace=0, page_is_redirect=0, old_id=10, cat egory=() page_title=???_??? page_namespace=0 8. document=5, weight=1648, page_namespace=0, page_is_redirect=0, old_id=181, ca tegory=() page_title=???_???_???_(???_???) page_namespace=0 9. document=2, weight=1608, page_namespace=8, page_is_redirect=0, old_id=1135, c ategory=() page_title=Sidebar page_namespace=8 10. document=12, weight=1608, page_namespace=0, page_is_redirect=0, old_id=719, category=() page_title=???_CRM page_namespace=0 11. document=71, weight=1608, page_namespace=0, page_is_redirect=0, old_id=701, category=() page_title=???_??? page_namespace=0 12. document=80, weight=1608, page_namespace=12, page_is_redirect=0, old_id=862, category=() page_title=???_CompanyNameWiki page_namespace=12 13. document=129, weight=1608, page_namespace=0, page_is_redirect=0, old_id=1085 , category=() page_title=??? page_namespace=0 words: 1. 'wiki': 13 documents, 37 hits В связи с тем, что имеется разница в кодировках — получили »???», а не русские буквы. НО главное- присутствует выдача. Значит поиск работает!
Вот собственно и все, мы установили sphinx, проиндексировали нашу базу данных и имеем работающий поисковый движок!
Автоматизация обновления индекса Для полной работы поиска необходимо также обеспечить регулярное обновление индекса — ведь статьи добавляются и необходимо обеспечить их доступность в поисковой выдаче в том числе.Для этого в планировщике заданий создадим задание с регулярностью запуска (у меня 5 минут) bat файла со следующим содержанием: c:\inetpub\wwwroot\mw\sphinx\bin\indexer --all --config c:\inetpub\wwwroot\mw\sphinx\bin\sphinx.conf --rotate
Я сделал запуск задания от имени локального администратора. Предварительно необходимо ЯВНО приписать права на всю папку sphinx.
Подключение поиска Sphinx в Mediawiki Теперь необходимо подключить поисковый движок к Mediawiki. Иначе последний ну никак не знает что искать надо не встроенным механизмом, а при помощи сфинкса.Идем в файл LocalSettings.php (Лежит в папке с медиавики) и там добавляем:
#Sphinx search $wgSearchType = 'SphinxMWSearch'; require_once »$IP/extensions/SphinxSearch/SphinxSearch.php»; $wgSphinxSearch_host = »127.0.0.1»; $wgSphinxSearch_port = 9312; $wgSphinxSearch_matches = 50; $wgEnableSphinxPrefixSearch = true; $wgFooterIcons['poweredby']['sphinxsearch'] = array ( 'src' => »$wgScriptPath/extensions/SphinxSearch/skins/images/Powered_by_sphinx.png», 'url' => 'http://www.mediawiki.org/wiki/Extension: SphinxSearch', 'alt' => 'Search Powered by Sphinx', ); Сохраняем. Перезапускаем сайт через менеджер IIS. Проверяем поиск руками через веб-страницу Mediawiki. Все должно работать.
Выдача при наборе текста в поисковой строке.
И сама поисковая выдача.
Заключение В итоге мы получили более качественный поиск по материалам в нашей вики.В выдаче по умолчанию сортировка принимает значение SPH_SORT_RELEVANCE.При желании ее можно изменить путем явного указания в файле LocalSettings.php через параметр$wgSphinxSearch_sortby
Подробнее о различных вариантах сортировки выдачи можно почитать в этом разделе документации.
В данной статье я использовал не только личные наработки, но и информацию, собранную в процессе реализации работы с данным механизмом поиска.
Я не рассматривал возможные ошибки, которые могут возникать в процессе т.к. посчитал правильным поделиться работающей конфигурацией, а также последовательностью действий, которые в итоге приводят к работе решения в целом. А ошибок этих было море- начиная от нехватки прав на файлы, «не тех» слешей и заканчивая неработоспособностью конфигурации Sphinx, поставляемой в комплекте с расширением.
