Поиск в Mediawiki при помощи Sphinx

image
Здравствуй, читатель!

Некоторое время назад мне была поставлена задача внедрения MediaWiki в корпоративной сети.
И главной проблемой этого внедрения стал поиск информации, содержащейся в вики.
В этой статье я хотел бы рассказать о том, как подружить поиск Sphinx с MediaWiki.
Причина по которой я хотел бы это написать — отсутствие русскоязычной документации и более-менее приличного руководства или описания, которое помогало бы моим коллегам быстро и просто начать использовать этот прекрасный поисковый механизм.
Возможно, я просто не умею пользоваться гуглом…

Зачем это нужно


Цель данного внедрения в нашей организации — перенос корпоративной базы знаний в более удобный формат представления и исправления\добавления.

К слову сказать — компания наша реализует проекты по автоматизации документооборота в комплексе.
Заказчики крупные, решения сложные и порой нестандартные.
И статьи в вики предполагается иметь не только о проектах, но и о технических решениях, фичах и т.п., инновационных методах и технологиях.
А также в планах использовать ее как источник информации для новых сотрудников- им предстоит изучить достаточно приличный объем информации и удобство доступа к ней в настоящий момент оставляет желать лучшего.

Как было сказано выше — за основу был взят популярный движок MediaWiki. А ключевой проблемой, которую я предсказывал еще в самом начале, стала проблема поиска информации.
Всем известно — стандартный поиск совсем плох. И закономерным стал вопрос — как исправить это недоразумение.

Подготовка


Итак, все развернуто на Windows Server 2012 R2 64bit, естественно поднят IIS:

image

Самые последние версии на момент установки. Расширение 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 (c) 2001-2014, Andrew Aksyonoff
       Copyright (c) 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 (c) 2001-2014, Andrew Aksyonoff
       Copyright (c) 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',
       );


Создаем в папке extensions новую папку с именем SphinxSearch.
важное замечание оставил vedmaka:
Добавлю: после установки sphinx нужно пойти на http://sphinxsearch.com/downloads/archive/, скачать оттуда исходники соответствующей версии и из них закинуть файл sphinxapi.php в директорию с SphinxSearch расширением.

Сохраняем. Перезапускаем сайт через менеджер IIS. Проверяем поиск руками через веб-страницу Mediawiki. Все должно работать.

image
Выдача при наборе текста в поисковой строке.

image
И сама поисковая выдача.

Заключение


В итоге мы получили более качественный поиск по материалам в нашей вики.
В выдаче по умолчанию сортировка принимает значение SPH_SORT_RELEVANCE.
При желании ее можно изменить путем явного указания в файле LocalSettings.php через параметр

$wgSphinxSearch_sortby

Подробнее о различных вариантах сортировки выдачи можно почитать в этом разделе документации.

В данной статье я использовал не только личные наработки, но и информацию, собранную в процессе реализации работы с данным механизмом поиска.

Я не рассматривал возможные ошибки, которые могут возникать в процессе т.к. посчитал правильным поделиться работающей конфигурацией, а также последовательностью действий, которые в итоге приводят к работе решения в целом. А ошибок этих было море- начиная от нехватки прав на файлы, «не тех» слешей и заканчивая неработоспособностью конфигурации Sphinx, поставляемой в комплекте с расширением.
  • +10
  • 11.4k
  • 4
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 4

    0
    Добавлю: после установки sphinx нужно пойти на sphinxsearch.com/downloads/archive/, скачать оттуда исходники соответствующей версии и из них закинуть файл sphinxapi.php в директорию с SphinxSearch расширением.
      0
      Точно! Забыл совсем! Без этого чуда не произойдет!
      Спасибо за комментарий! Добавил
      0
      а зачем вы сфинкс поставили в общедоступную директорию сайта то? Ну хоть бы в какой нить Program files чтоли закинули
        0
        А с чего вы решили что папка общедоступна? При попытке просмотра ее, при попытке обращения к любому файлу вы получаете 404 в ответ. Все нормально.

      Only users with full accounts can post comments. Log in, please.