Люська, будь с нами!
От: akasoft Россия  
Дата: 22.11.06 19:07
Оценка: 266 (17) :)))
Был такой голливудский фильм, в котором мертвецы понуро брели за главными героем и героиней, а также и за редкими по ходу фильма живыми людьми, протягивали к ним руки и ужасным хрипом призывали: "Будь с нами!". По ходу фильма казалось, что неизбежно мертвецы победят, но конец был счастливый.

В роли "мертвецов" конечно же не теряющие надежду снова обрести быстрый поиск янусопоклонники, а в роли героини Люськи сегодня выступает порт под .NET поисковой системы Lucene.

Если кто не понял, это я про поиск в Янусе.

Вступление

Тут
Автор: akasoft
Дата: 18.06.06
совсем рядом я как-то втирал про поиск, то, сё, и в ходе дискуссии АВК упомянул lucene, как хороший механизм поиска для Януса. И конечно же, я с ним не согласился , но, поскольку реструктуризатора ЛБД не было (и всё ещё и нет), то я "от нечего делать" пошёл посмотреть, что это за люсьена такая. Оказалось, что она мало того, что под .NET 1.1, мало того, что индекс какой-то хранит в каких-то файлах, так ещё и по русскоязычной кирилице искать не умеет. Это не считая "существенного недостатка", АВК меня поймёт. Было это дело в июне 2006 года.

Недавно товарищ Сухов напомнил мне про люсьену ещё раз
Автор: Igor Sukhov
Дата: 14.11.06
. Как оказалось, теперь в ней появился анализатор для русского языка. Что, естественно, существенно меняет дело.

Собственно, товарищу Сухову мы обязаны обретением быстрого поиска в Янусе, а здесь
Автор: Igor Sukhov
Дата: 15.11.06
даже есть реализация для MSSQL с описанием.

Конечно же, я не мог всё не переделать.

Адаптация люсьены к FW 2.0

Адаптацию люсьены под FW 2.0 выполнила за меня VS2005. Я просто открыл её файл проекта, тут же выскочил вежливый Мастер и предложил сделать upgrade. Я согласился, получил более 70 предупреждений, всякие перлы вида "in_Renamed, string_Renamed" и т.п. Потом скомпилировал это дело (без ошибок) в Release и получил два файла: Lucene.Net.dll и Lucene.Net.xml. А затем включил их в проект.

Важной особенностью тут является то, что по умолчанию папка \Lucene.Net\Analysis\RU\ в проект не включена (и об этом писал Сухов), поэтому её надо подключить вручную. Видимо, из вредности её так. Но хорошо, что есть вообще.

Также есть папка DE, видимо, для немецкого, а на апаче есть и другие анализаторы, пока не портированные на .NET.

Особенности реализации и использования

Использование люсьеновского индекса включается флажком Общие — Использовать lucene в настройках приложения. По умолчанию он отключен, и при этом невозможно ни построить начальный индекс, ни производится актуализация индекса при синхронизации. Для поиска используется старый проверенный LIKE-based способ. Практически obsolete и deprecated.

Также в настройках добавился параметр Общие — Максимум записей при поиске, служит для ограничения выборки результата поиска с помощью костыля SqlBuilder.Top(), как это сделано в Document explorer. По умолчанию используется 500 записей. Если установить в 0, то ограничение не накладывается. На РСДН в сутки по всем форумам бывает 2 — 2.5 тыс. сообщений. Этот параметр действует для обоих механизмов поиска.

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

Индекс включает в себя поля mid, gid, dte, subject, uid, usernick, message. Сохраняется в индексе только mid, потом по нему выбираются нужные документы. Индекс довольно компактен: для 3.4 ГБ ЛБД SQL Express >1.7 млн. сообщений его объём — 388 МБ. Токенизированы (т.е. можно искать по словоформам) текст, тема и автор сообщения. С именами авторов иногда прикольно получается.

Люсьеновский индекс хранится в отдельной папке под названием ".index", которая ложится в папку с конфигурационными файлами (и janus.mdb, если используеется access), имя изменить нельзя.

По нажатию на кнопку Искать вначале вызывается люсьеновский поиск, и если с её помощью ничего не найдено, то дальше уже ничего не происходит. Если же найдено, то дополнительно проверяются флажки Поиск в пометках и Поиск в вопросах, и формируется SQL-запрос на выборку с учётом этих полей и списка mid, найдённого люсьеной, с учтом ограничения на выборку "поле IN (список)" (DatabaseManager._maxInClauseElements).

Обычно у янусопоклонников уже есть некоторая ЛДБ, но ситуация с отсутствующим начальным индексом при синхронизации будет отработана корректно, т.е. он будет создан.

Для построения начального индекса сделана отдельная модальная форма, вызываемая из меню Сервис — Построить поисковый индекс. При необходимости индекс можно перестроить заново, для чего удаляется предыдущий с помощью кнопки Очистить (либо вручную).

Построение индекса запускается по кнопке Начать и может быть прервано кнопкой Остановить. Затем можно выключить компьютер, а на следующий день достроить индекс.

Индекс следует строить при отключенной автосинхронизации, она не приведёт к краху, но может добавить в индекс дубли документов.

Начальный индекс строится от наибольшего mid к наименьшему (от max(mid) к min(mid)), что позволяет сразу получить доступ к поиску по свежим сообщениям, плюс у обладателей больших и полных (подписка на всё) ЛБД так больше шансов, что синхронизация принесёт только новые сообщения.

Построение начального индекса можно прерывать и продолжать, при этом просмотр сообщений всегда начинается порциями с начала, но каждая порция проверяется (с помощью Lucene-поиска, потому и быстро) на наличие каждого сообщения в индексе, и в случае наличия сообщение пропускается. Такой механизм позволяет начать построение индекса, затем прервать его, произвести пару синхронизаций, затем продолжить. Включенные при синхронизации сообщения переиндексированы не будут. Пропуск происходит довольно шустро (10 мин на 800 тыс. сообщений).

Актуализации индекса при синхронизации происходит после реального добавления данных в ЛДБ, но на основе полученных и имеющихся в памяти данных DataSet, что быстрее. Исключение при синхронизации также блокирует и индексацию, как и исключение при добавлении данных в ЛДБ. При актуализации считается, что самые точные данные находятся в полученном DataSet, поэтому из индекса сначала удаляются документы с имеющимися mid, а затем добавляются, но с учётом того, что есть две корзины-мусорки, данные из которых в ЛБД не попадают. (Но ведь передаются, а потому чего бы не завести корзину и в ЛДБ...) Таким образом видно количество модераторских правок и перезагрузок сообщений, а также количество пришедших сообщений в целом, а не только новых.

В случае пропадания света индекс не обязательно испортится, равно как и в случае наложения автосинхронизации. Люсьена поддерживает многопользовательскую работу с индексом, не только на чтение (поиск), но и на запись (актуализация). Использование рассинхронизированного индекса и ЛБД (построили индекс дома, принесли на работу) также возможно, просто часть mid в ЛБД может отсутствовать в результатах, но искаться будет.

Периодически стоит заходить на форму построения индекса, взводить флажок "Оптимизировать индекс при останове", заускать и затем прерывать индексацию. При этом будет устраняться фрагментация индекса, реально удаляться удалённые при актуализации сообщения (как в DBF), и пр. При этом требуется 2 раза по столько места, сколько занимает индекс (папка .index). Раз в неделю или раз в месяц. После оптимизации в папке будет оставаться один большой фрагмент и пара служебных файлов.

Код доступен в репозитории.

Поисковые возможности

Поисковые возможности люсьены очень богаты. Поиск при включенной люсьене отличается от LIKE-поиска, и я не стал адаптировать его к старым привычкам.

При LIKE-поиске
Автор: akasoft
Дата: 14.09.03
мы указывали фрагменты слов, не обязательно с начала слова, через пробел, и найдённые документы был обязаны содержать все эти фрагменты (режим AND), а флажок Любое из слов позволял режим OR.

В люсьене пробел считается за OR, а указание начала слова является обязательным, окончание можно опускать (хотя, лучше указывать полностью, как в Гугле). Поэтому перед каждым словом нужно писать плюсик (+).

Также у люсьены есть целый набор спецсимволов. Например, круглые скобки используются для группирования условий поиска (почти как для if в C). Чтобы использовать в поиске спецсимволы люсьены, их нужно префиксировать слешем (\), иначе случится исключение.

Префиксировать нужно:
+ - && || ! ( ) { } [ ] ^ " ~ * ? : \


Важное замечание: Люсьена не любит пустые строки запросов, поэтому если вы не укажите ничего в поле "Ищем", то будет задействован LIKE-поиск. Укажите там что-либо, букову какую (не пробел), а флажки Поиск в тексте, теме и автора не ставьте.

Ищем...Было для LIKEСтало для люсьены
Сообщение со словами rsdn И magazinersdn magazine+rsdn +magazine
Сообщение со словами rsdn ИЛИ magazinersdn magazine, плюс флажок Любое из словrsdn magazine
Сообщение со словами rsdn И magazine, но без слова заказневозможно+rsdn +magazine -заказ
Поиск фразы "исправление ошибок" с учётом морфологииневозможно"исправление ошибок"
Следим за модераторами кодт и andrewvkневозможно+"перенесено модератором" +(andrewvk кодт)
Следим за модераторами кодт и andrewvkневозможно+"ветка выделена из темы" +(andrewvk кодт)
Ищем всех пользователей, ники которых начинаются с andreandreandre*
А теперь пользователей, ники которых начинаются с andrew и имеют двухсимвольный суффиксневозможноandrew??
Поиск упоминания функции .EnableVisualStyles().EnableVisualStyles().EnableVisualStyles\(\)
Поиск упоминания функции String.Format() с параметрами (!) что-то типа string.format(string.format\(\)
Поиск упоминания функции Convert.ToString() и её же с конкретизацией параметра, например, указанием приведения к int — Convert.ToString((int)) (!) затрудняюсь придуматьConvert.ToString\(\(int\)\)
Более продвинутой техникой является использование префиксов полей. Я их специально указал в начале, повторю: "mid, gid, dte, subject, uid, usernick, message". Достаточно поставить галочку поиск в тексте, а затем можно отдельно префиксировать слова в полях тема или автор.

Мы хотим найти сообщения о будущем nemerle от Влада Чистякова, взводим галочку поиска по тексту и пишем+будущее +nemerle +usernick:vladd2
А теперь хотим того же, но только не от Влада:+будущее +nemerle -usernick:vladd2
Чтобы найти сообщения от Влада к Губанову про оберон, используя тот факт, что по умолчанию сообщение начинается со слов "Здравствуйте, Сергей Губанов, вы писали". Их, на удивление, немного. +губанов +оберон +usernick:vladd2

Полезные ссылки

  1. Собственно, сам порт люсьены и документация (к слову, левая, лучше книгу почитать, что ниже и использовать object browser) http://incubator.apache.org/lucene.net/
  2. Книга по использованию люсьены, для явы, но примеры легко читаются и под шарп, есть архив с кодом примеров на яве и примеры глав, на рапидшаре есть полный .pdf http://lucenebook.com/
  3. Описание поискового синтаксиса, на английском http://www.dotlucene.net/documentation/QuerySyntax.html
  4. Просто интересный ресурс со ссылками и документацией http://swik.net/Lucene.Net
  5. Пример приложения для офиса на .NET, использующего люсьену, служба для построения индекса (PPT, DOC, XLS, HTM/HTML, TXT, PDF, VSD, RTF, XML, etc) и клиентское приложение, с исходным кодом, но буржуи это скомпилировали без RussianAnalyzer(), надо перекомпилировать и всё пучком http://www.seekafile.org/
  6. А здесь у zend хоть и про php, но и про люсьену и оптимизацию, и на русском http://framework.zend.com/manual/ru/zend.search.index-creation.html

Про оптимизацию можно почитать ещё и тут
Автор: akasoft
Дата: 20.11.06
, а по поводу MergeFactor есть такое наблюдение, что он влияет на размер файлов сегментов индексов и частоту их сливания в один файл. Так, при 10 в папке индекса замечены файлы размера около 1МБ, по появлению десяти таких файлов они сливаются в один файл в 10 МБ, и опять плодятся по одному, наплодившись 10 опять сливаются в один, по появлению 10 файлов по 10 МБ сливаются в один в 100 МБ, и т.п. Т.е. шаг 1, 10, 100 МБ. Возможно, также используется 0.1, 0.01 МБ.

Файлы

Для тех, кто хочет попробовать "прямо сейчас", выложил архив (710 МБ) с релизной сборкой Janus.exe и Lucene.Net.dll, остальное не менялось. Вроде бы. Если что, стучать Шеридану.

Вместо послесловия

Тут хочу выразить благодарность тов. Игорю Сухову за своевременное напоминание про люсьену, за пример кода и за настойчивость.

Как обычно, картинки на кнопки рисовать не умею, но хотелось бы видеть нечто, напоминающее про то, что в поиске в Янусе используется люсьеновский движок.

Заводить для поиска отдельную ветку в конфиге пока не стал.
... << RSDN@Home 1.2.0 alpha rev. 667>> SQL Express 2005
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.