Новые возможности Apache Solr

Использование новых возможностей, появившихся в Solr 1.3

С момента опубликования статей серии Умный поиск при помощи Apache Solr в Apache Solr появилось множество новых возможностей, а также было существенно улучшено быстродействие. В этой статье Грант Ингерсолл – один из разработчиков Solr и Lucene – подробно расскажет о преимуществах Solr 1.3, в том числе о таких новых функциях, как распределенный поиск, упрощение импорта баз данных, встроенная поддержка орфографии, расширенные API и многих других.

Грант Ингерсолл, технический специалист, Lucid Imagination

Grant IngersollГрант Ингерсолл (Grant Ingersoll) является основателем и техническим сотрудником компании Lucid Imagination. Его профессиональные интересы как разработчика включают такие вопросы, как информационный поиск, машинное обучение, категоризация и извлечение текста. Кроме того, Грант является разработчиком и представителем проектов Apache Lucene и Apache Solr, а также одним из основателей проекта Apache Mahout, посвященного машинному обучению.



12.07.2010

Apache Solr представляет собой поисковый сервер с открытым исходным кодом, основанный на Apache Lucene и работающий преимущественно через протокол HTTP. В 2007 г. на сайте developerWorks была опубликована серия из двух статей под названием Умный поиск при помощи Apache Solr, в которых содержалась вводная информация о Solr. Однако после выпуска версии 1.3 пришло время описать множество новых возможностей и усовершенствований, появившихся с тех времен.

Solr предоставляет множество функций, делающих его пригодным для использования в корпоративных приложениях, а именно: поддержку простого конфигурирования и администрирования, поддержку множественных связей между клиентами и языками, репликацию индексов, кэширование, статистику и журналирование. Кроме того, в версии 1.3 существенно улучшена производительность благодаря громадному прогрессу в быстродействии Apache Lucene 2.3, а также использованию новой обратно совместимой и встраиваемой компонентной архитектуре. Данная архитектура послужила основанием для появления большого числа новых компонентов, которые дополнительно расширяют возможности Solr. Например, в релиз 1.3 вошли следующие компоненты:

  • проверка орфографии с поддержкой функции "Вы, наверное, имели в виду следующее?";
  • поиск документов по принципу схожести;
  • возможность переопределения результатов поиска (так называемое "платное размещение").

Более того, даже существующая функциональность, например разбор запросов, поиск, сегментирование и отладка, была переработана с учетом компонентного подхода, который позволяет разработчикам создавать собственные обработчики (экземпляры SolrRequestHandler) путем сцепления компонентов. Наконец, в Solr появилась возможность непосредственной индексации содержимого базы данных. Это очень важно для многих корпоративных приложений, так как позволяет осуществлять распределенный поиск по очень большим хранилищам данных.

Несмотря на то что в статье приводится краткий обзор Solr, подразумевается, что читатели знакомы с базовыми понятиями данной технологии, в частности, с файлами schema.xml, solrconfig.xml, основами индексирования и поиска, а также представляют себе, зачем нужны экземпляры SolrRequestHandler. Если вы с этим незнакомы, то имеет смысл прочитать серию Умный поиск при помощи Apache Solr, ссылка на которую приведена в разделе Ресурсы.

Мы начнем с краткого описания ключевых моментов в Solr, а затем перейдем к последней версии и ее установке (в том числе к некоторым моментам перехода с предыдущей версии). Далее мы рассмотрим некоторые из главных улучшений по сравнению с предыдущим релизом и закончим обзором некоторых новых функций Solr.

Основы Solr

По существу, Solr можно рассматривать как совокупность четырех основных компонентов:

  • схема (schema.xml);
  • конфигурация (solrconfig.xml);
  • индексирование;
  • поиск.

Для того чтобы понять, что представляет собой схема, необходимо обратиться к Lucene и его понятию документа. Document – это набор из одного или более полей (Field), каждое из которых состоит из имени, содержимого и метаданных, описывающих то, как следует обрабатывать содержимое. Поиск по содержимому осуществляется путем его анализа, который выполняется последовательно цепочкой из экземпляров Tokenizer и, возможно, TokenFilter. Первые могут разделять входной поток на отдельные слова (токены), а вторые – модифицировать токены (например, выделять корни слов) либо удалять их. Схема Solr позволяет легко настраивать процесс анализа документов без написания кода. Кроме того, поддерживается возможность строгой типизации полей, например можно указать, что типом поля является String, int, float или любой другой примитивный или специальный тип данных.

Что касается конфигурации, то в файле solrconfig.xml можно указывать, каким образом Solr должен индексировать, подчеркивать, сегментировать, осуществлять поиск и обрабатывать другие запросы. При помощи атрибутов можно управлять кэшированием и использованием индексов в Lucene. Конфигурация может зависеть от схемы, но не наоборот.

Индексирование и поиск осуществляются в ответ на HTTP-запросы, полученные сервером Solr. Для индексирования достаточно отправить через POST-запрос документ XML, в котором описывается каждое поле и его содержимое. Пример такого документа можно найти в файле hd.xml, расположенном в каталоге apache-solr-1.3.0/example/exampledocs/ (листинг 1).

Листинг 1. Пример документа XML
<add>
<doc>
  <field name="id">SP2514N</field>
  <field name="name">Samsung SpinPoint
   P120 SP2514N -
  hard drive - 250 GB - ATA-133</field>
  <field name="manu">Samsung Electronics 
  Co. Ltd.</field>
  <field name="cat">electronics</field>
  <field name="cat">hard drive</field>
  <field name="features">7200RPM, 
  8MB cache, IDE Ultra ATA-133</field>
  <field name="features">NoiseGuard, 
  SilentSeek technology, Fluid
  Dynamic Bearing (FDB) motor</field>
  <field name="price">92</field>
  <field name="popularity">6</field>
  <field name="inStock">true</field>
</doc>
</add>

Для поиска достаточно отправить GET-запрос через HTTP (ниже приведен пример URL).

http://localhost:8983/solr/select?indent=on&version=2.2&q=ipod&start=0&rows=10
      &fl=*%2Cscore&qt=standard&wt=standard

В этом примере отправляется запрос с именем ipod, причем размер выборки ограничивается десятью записями. В страницах wiki можно найти более подробную информацию по различным параметрам запросов (см. раздел Ресурсы). В последнем релизе Solr содержится клиентское приложение SolrJ, которое позволяет скрывать все низкоуровневые детали формирования HTTP-запросов за фасадом из Java™-классов. О SolrJ мы поговорим ниже в этой статье.

На этом мы заканчиваем краткий обзор основных понятий Solr. Этого должно хватить для понимания общей архитектуры Solr.


Установка Solr 1.3

Для работы с Solr, в частности для запуска примеров к этой статье, необходимо установить следующее программное обеспечение:

  • Java версии 1.5 или выше;
  • Web-браузер для просмотра страниц администрирования. Мы будем использовать Firefox, но подойти должны почти все современные браузеры;
  • для запуска примера DataImportHandler понадобится база данных и JDBC-драйвер к ней. В статье будет использоваться PostgreSQL, хотя другие СУБД, например MySQL, также будут работать, но не исключено, что придется модифицировать SQL-запросы;
  • контейнер сервлетов. Мы будем использовать Jetty, который входит в стандартную поставку Solr, поэтому нет необходимости устанавливать другой контейнер. Однако если вы привыкли использовать Tomcat или что-то еще, то Solr можно настроить для работы с другим сервером.

Первоначальная установка Solr

После того как вы установили все необходимые приложения, загрузите Solr 1.3.0, выбрав одно из зеркал на Web-сайте Apache, и распакуйте архив в каталог по вашему выбору. В результате вы должны увидеть директорию apache-solr-1.3.0. Перейдите в нее и выполните следующие команды из командной строки.

  1. cd apache-solr-1.3.0/example (используйте \, если вы работаете под Windows®).
  2. java -jar start.jar.

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

    2008-10-01 09:57:06.336::INFO:  Started SocketConnector @ 0.0.0.0:8983
    Oct 1, 2008 9:57:06 AM org.apache.solr.core.SolrCore registerSearcher
    INFO: [] Registered new searcher Searcher@d642fd main
  3. Загрузите в браузере страницу по адресу http://localhost:8983/solr. Если все нормально, то вы должны увидеть приветствие Solr.
  4. В другом окне интерпретатора выполните команду cd apache-solr-1.3.0/example/exampledocs.
  5. java -jar post.jar *.xml. Это автоматически добавит набор документов в Solr.
  6. Попробуйте выполнить запрос из административной страницы в браузере (http://localhost:8983/solr/admin/form.jsp).

    На рисунке 1 показаны сокращенные результаты запроса ipod на моем компьютере.

    Рисунок 1. Пример результатов запроса
    Sample Search Results

Теперь сервер Solr 1.3 запущен и готов к работе. Ниже мы будем работать с примерами файлов solrconfig.xml и schema.xml, которые расположены в каталоге apache-solr-1.3.0/example/solr/conf. Однако перед этим мы рассмотрим некоторые вопросы перехода на 1.3 с более ранних версий Solr, а затем – усовершенствования последней версии. Если вам не требуется делать такой переход, то вы можете пропустить раздел Расширение функциональных возможностей.

Переход с ранних версий Solr

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

Репликация в Solr

Ресурсы

Во-вторых, в Solr 1.3 используется новая версия Lucene. Фактически это означает, что Solr преобразует внутренние файлы к новому формату Lucene, что может привести к тому, что предыдущие версии Solr не смогут их прочитать. Вследствие этого следует сделать резервную копию индексных файлов перед установкой, на случай того, если вы в будущем захотите вернуться к предыдущей версии.

В-третьих, в состав Solr 1.3 также входит новая версия стеммера (утилиты для выделения основ слов) Snowball Мартина Портера (Dr. Martin Porter). Существует небольшая вероятность того, что выделение основ слов в этой версии в некоторых случаях может отличаться от предыдущих, поэтому лучше переиндексировать содержимое, чтобы исключить возможность несоответствий между результатами анализа во время индексации и во время выполнения поиска.

За исключением этих моментов, с которыми может столкнуться часть пользователей, переход на Solr 1.3 должен проходить безболезненно. Теперь мы можем переходить к основной теме статьи, начав с функциональности Solr, которая была усовершенствована в новой версии.


Расширение функциональных возможностей

Solr 1.1 и 1.2 были неплохими продуктами, однако, как и большинство приложений (за исключением самых простейших), они оставили обширное пространство для дальнейшего развития. В Solr 1.3 было исправлено множество ошибок и, кроме того, было повышено быстродействие и стабильность работы сервера.

Повышение производительности

Первым и главным моментом является то, что в последнем релизе Solr используются свежие версии библиотек Lucene, в которых значительно улучшена производительность. На моих тестах можно наблюдать пятикратное ускорение индексирования, а также от двух- до восьмикратного ускорения остальных задач. К счастью, ускоренное индексирование будет работать для абсолютно всех пользователей Solr, да и большинство остальных усовершенствований не потребует изменения конфигурационных настроек.

Однако существует один конфигурационный параметр, легко задающийся в файле solrconfig.xml, при помощи которого можно более гибко выделять память для процесса индексирования. В версиях 1.1 и 1.2 проиндексированные документы записывались на диск, если их число в памяти превышало определенное пороговое значение, причем размер документов при этом не имел никакого значения. В результате память часто использовалась неэффективно, например документы небольшого размера могли записываться слишком часто, несмотря на доступность памяти, либо наоборот – недостаточно часто в случае крупных документов. Теперь вместо числа документов можно указывать объем, выделяемый под их хранение в памяти, при помощи параметра <ramBufferSizeMB> в секции <indexDefaults> файла solrconfig.xml.

Дополнительные возможности расширения Solr

В Solr 1.3 стало значительно проще создавать, конфигурировать и управлять расширениями. В предыдущих версиях для того чтобы добавить новую функциональность, необходимо было создать новый обработчик SolrRequestHandler. При этом основной проблемой была трудность повторного использования возможностей других объектов SolrRequestHandler. Например, представьте, что вы хотите реализовать собственный вариант сегментирования, сохранив при этом существующие реализации обработки запросов и подсветки результатов. Теперь для решения подобных задач Solr позволяет разделять обработчики (например, StandardRequestHandler или DismaxRequestHandler) на компоненты (SearchComponent), которые затем можно соединять в цепочку при реализации нового обработчика. Таким образом, в новой версии Solr можно сосредоточиться на реализации только нужного объекта SearchComponent, не отвлекаясь на вопросы расширения, повторного использования или репликации существующей функциональности.

При этом не стоит волноваться за существующих наследников SolrRequestHandler – они будут работать, как и ранее, просто теперь они будут представлять собой классы-обертки над компонентами SearchComponent, выполняющими соответствующие действия. Информация по некоторым из компонентов приведена в таблице 1. Ниже мы более подробно рассмотрим два из них: MoreLikeThisComponent и SpellCheckComponent. Ссылка на класс SearchComponent также приведена в разделе Ресурсы.

Таблица 1. Часто используемые классы SearchComponent
alt-rowalt-rowalt-row
НазваниеОписание и пример запроса
QueryComponentОтвечает за отправку запроса Lucene и возврат списка объектов Document

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10
FacetComponentОпределяет категории для результатов запросов

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10&facet=true&facet.field=inStock
MoreLikeThisComponentДля каждого полученного результата выполняет поиск похожих документов и возвращает их список

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10&mlt=true&mlt.fl=features&mlt.count=1
HighlightComponentВыделяет цветом ключевые слова поиска в тексте документов, полученных в качестве результатов

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10&hl=true&hl.fl=name
DebugComponentВозвращает информацию о разборе запроса, а также подробности ранжирования найденных документов

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10&debugQuery=true
SpellCheckComponentПроверяет орфографию запроса и предлагает возможные альтернативы на основе содержимого индекса

http://localhost:8983/solr/spellCheckCompRH?&q=iPood&start=0&rows=10&spellcheck=true&spellcheck.build=true

По умолчанию все классы SolrRequestHandler содержат компоненты QueryComponent, FacetComponent, MoreLikeThisComponent, HighlightComponent и DebugComponent. Для добавления своего собственного компонента необходимо сделать следующее:

  1. Создать класс, расширяющий SearchComponent.
  2. Сделать его доступным для использования в Solr (ссылка на страницу wiki, описывающую модули подключения в Solr, приведена в разделе Ресурсы).
  3. Произвести нужные настройки в файле solrconfig.xml.

Допустим, мы создали класс com.grantingersoll.MyGreatComponent, сделали его наследником SearchComponent и подготовили для использования в Solr. Далее необходимо вставить его в SolrRequestHandler, чтобы к нему можно было обращаться с запросами. Для этого вначале необходимо объявить компонент, чтобы Solr мог инстанциировать класс (листинг 2).

Листинг 2. Объявление компонента
  <searchComponent name="myGreatComp" class="com.grantingersoll.MyGreatComponent"/>

Далее следует указать, какому классу SolrRequestHandler должен принадлежать данный компонент. Это можно сделать следующими способами:

  • явно объявить все классы SearchComponent, как показано в листинге 3;
    Листинг 3. Явное объявление всех компонентов ( SearchComponent)
    <requestHandler name="/greatHandler" class="solr.SearchHandler">
        <arr name="components">
          <str>query</str>
          <str>facet</str>
          <str>myGreatComp</str>
          <str>highlight</str>
          <str>debug</str>
        </arr>
    </requestHandler>
  • добавить компонент в начало существующей цепочки компонентов (листинг 4);
    Листинг 4. Добавление компонента в начало цепочки
    <requestHandler name="/greatHandler" class="solr.SearchHandler">
        <arr name="first-components">
          <str>myGreatComp</str>
        </arr>
    </requestHandler>
  • добавить компонент в конец существующей цепочки компонентов (листинг 5).
    Листинг 5. Добавление компонента в конец цепочки
    <requestHandler name="/greatHandler" class="solr.SearchHandler">
        <arr name="last-components">
          <str>myGreatComp</str>
        </arr>
    </requestHandler>

Замечание о классе DebugComponent

При использовании вариантов на основе first-components или last-componentsDebugComponent должен быть последним компонентом в цепи. Это особенно важно, если другие компоненты могут менять отладочные значения, которые выводятся DebugComponent, например результаты запроса.

В Solr 1.3 также можно выносить разбор запросов за пределы SolrRequestHandler. Это делается аналогично разделению обработчиков на компоненты. Таким образом, теперь можно использовать DismaxQParser с любым классом SolrRequestHandler. Для этого достаточно указать нужное значение параметра defType в запросе (см. пример ниже).

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10&defType=dismax&qf=name

В этом примере для разбора запроса используется парсер Dismax вместо стандартного парсера Lucene.

Кроме того, можно создать собственный парсер запросов, расширив классы QParser и QParserPlugin, сделав их доступными для Solr и произведя нужные настройки в solrconfig.xml. Ниже показан пример конфигурирования парсеров com.grantingersoll.MyGreatQParser и com.grantingersoll.MyGreatQParserPlugin в solrconfig.xml.

<queryParser name="greatParser" class="com.grantingersoll.MyGreatQParserPlugin"/>

Теперь можно отправлять запросы к новому парсеру, указывая в URL параметр defType=greatParser.

Это далеко не полный перечень усовершенствований, вошедших в последний релиз Solr. Более подробно они перечислены в примечаниях к релизу (release notes), которые можно найти по ссылке в разделе Ресурсы. Далее мы рассмотрим новые функции Solr.


Новые возможности

В Solr 1.3 появился ряд новых возможностей, делающих его как никогда привлекательным. В оставшейся части статьи мы рассмотрим эти функции, а также варианты их использования в приложениях. Для этого мы создадим простое приложение для подписки и выставления оценок RSS-ленте. Оценки будут храниться в базе данных, а сама лента будет браться из моего блога, посвященного Lucene. На этом незамысловатом примере будут продемонстрированы следующие компоненты Solr:

Далее загрузите демонстрационное приложение и выполните следующие действия:

  1. Скопируйте файл sample.zip в каталог apache-solr-1.3.0/example/.
  2. Распакуйте файл sample.zip.
  3. Запустите (или перезапустите) Solr: java -Dsolr.solr.home=solr-dw -jar start.jar.
  4. Подключившись к СУБД с правами администратора, создайте пользователя с именем solr_dw (этот процесс должен быть описан в документации по вашей СУБД). В PostgreSQL для этого достаточно выполнить команду create user solr_dw;.
  5. Создайте базу данных с именем solr_dw, владельцем которой будет этот пользователь: create database solr_dw with OWNER = solr_dw;.
  6. Выполните следующий скрипт src/sql/create.sql из командной строки: psql -U solr_dw -f create.sql solr_dw. Вы должны увидеть следующее:
     gsi@localhost>psql -U solr_dw -f create.sql solr_dw
    psql:create.sql:1: ERROR:  table "feeds" does not exist
    psql:create.sql:2: NOTICE:  CREATE TABLE / PRIMARY KEY will create \
      implicit index "feeds_pkey" for table "feeds"
    CREATE TABLE
    INSERT 0 1
    INSERT 0 1
    INSERT 0 1
    INSERT 0 1
    INSERT 0 1

Импорт информации из баз данных и других источников

В наш век, характерной чертой которого является наличие больших объемов структурированных и неструктурированных данных, часто необходимо импортировать информацию, хранящуюся в базах данных, файлах XML/HTML и других источниках, и делать ее доступной для поиска. Ранее для этого было необходимо писать специальные программы, подключающиеся к базам данных, файловым системам или RSS-лентам. Теперь же эти функции берет на себя обработчик DataImportHandler (DIH), входящий в состав Solr, предоставляя доступ к информации в БД (через JDBC), лентах RSS, Web-страницах и других файлах. Этот обработчик находится в каталоге apache-1.3.0/contrib/dataimporthandler и распространяется в виде JAR-файла apache-1.3.0/dist/apache-solr-dataimporthandler-1.3.0.jar.

Особенности DataImportHandler

Обработчик DataImportHandler не является поисковым роботом, и он не может самостоятельно извлекать содержимое из двоичных файлов, таких как MS Office, Adobe PDF и других закрытых форматов. Кроме того, обсуждение всех деталей работы DIH выходит за рамки этой статьи. Ссылки на источники более подробной информации приведены в разделе Ресурсы.

Он состоит из нескольких основных частей:

  • источник данных (DataSource): может представлять собой базу данных, Web-страницу, RSS-ленту или XML-файл;
  • объявления документов/сущностей: они описывают соответствие между содержимым источника данных и схемой Solr;
  • импорт: команда Solr, которая выполняет либо полный импорт данных, либо так называемый дельта-импорт, при котором импортируются только измененные сущности;
  • EntityProcessor модуль, отвечающий за преобразование данных при импорте. В состав Solr входят следующие четыре стандартные реализации:
    • FileListEntityProcessor: импортирует все файлы в заданном каталоге;
    • SqlEntityProcessor: подключается к базе данных и импортирует записи;
    • CachedSqlEntityProcessor: добавляет поддержку кэширования к классу SqlEntityProcessor.;
    • XPathEntityProcessor: извлекает содержимое XML-файлов при помощи XPath;
  • Transformer: необязательный модуль, предоставляемый пользователем для преобразования импортируемого содержимого перед его загрузкой в Solr. Например, при помощи класса DateFormatTransformer можно приводить формат дат к некоторому единому представлению;
  • подстановка значений переменных: меняет имена переменных на их значения на этапе выполнения.

Для начала необходимо сконфигурировать SolrRequestHandler для связывания DIH с Solr. Это делается в файле solr-dw/rss/conf/solrconfig.xml, как показано в листинге 6.

Листинг 6. Связывание DIH с Solr
<requestHandler name="/dataimport"
  class="org.apache.solr.handler.dataimport.DataImportHandler">
<lst name="defaults">
  <str name="config">rss-data-config.xml</str>
</lst>
</requestHandler>

Эти настройки говорят о том, что данный обработчик будет принимать запросы по URI http://localhost:8983/solr/rss/dataimport, а его конфигурационные параметры будут храниться в файле rss-data-config.xml. Как видите, ничего сложного.

Немного забегая вперед, скажем, что rss-data-config.xml – это тот файл, в котором объявлены и используются источники данных, сущности и экземпляры Transformer (преобразователи). В этом примере объявления источников данных содержатся в первых двух элементах XML (листинг 7).

Листинг 7. Объявления DataSource
<dataSource name="ratings" driver="org.postgresql.Driver"
      url="jdbc:postgresql://localhost:5432/solr_dw" user="solr_dw" />
<dataSource name="rss" type="HttpDataSource" encoding="UTF-8"/>

Первым в листинге 7 идет объявление экземпляра DataSource, который будет соединяться с базой данных. Он назван ratings (оценки), потому что в базе данных хранится информация об оценках RSS-лент. Обратите внимание, что пароль для этого пользователя не указан, однако для этого можно добавить тег password. Объявление DataSource должно выглядеть знакомо для тех из вас, кто выполнял настройку JDBC-подключений. Второй источник данных (rss) будет использоваться для получения информации через HTTP. URL для этого DataSource будет объявлен ниже.

Следующим элементом, представляющим интерес, является <entity>. Именно в этих тегах указывается преобразование содержимого RSS-ленты или базы данных в набор документов (Document) Solr. Сущность представляет собой некую единицу содержимого, которая должна индексироваться как самостоятельный документ. Например, в случае базы данных объявление сущности описывает преобразование каждой записи в набор полей (Field) документа. Сущности могут содержать дочерние сущности, при этом подобная иерархическая структура преобразуется в плоский набор полей документа.

Далее мы рассмотрим аннотированный пример файла rss-data-config.xml, на котором будут проиллюстрировано большинство деталей описания сущностей. В этом примере главная сущность описывает содержимое RSS-ленты и сопоставляет его со строками в базе данных для получения информации об оценках. Сокращенная версия RSS-ленты приведена в листинге 8.

Листинг 8. Фрагмент RSS-ленты
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
>
<channel>
<title>Grant's Grunts: Lucene Edition</title>
<link>http://lucene.grantingersoll.com</link>
<description>Thoughts on Apache Lucene, Mahout,
    Solr, Tika and Nutch</description>
<pubDate>Wed, 01 Oct 2008 12:36:02 +0000</pubDate>
<item>
  <title>Charlotte JUG >> OCT 15TH - 6PM -
    Search and Text Analysis</title>
  <link>http://lucene.grantingersoll.com/2008/10/01/
    charlotte-jug-%c2%bb-oct-15th-
    6pm-search-and-text-analysis/</link>
  <pubDate>Wed, 01 Oct 2008 
  12:36:02 +0000</pubDate>
  <category><![CDATA[Lucene]]></category>
  <category><![CDATA[Solr]]></category>
  <guid isPermaLink="false">http://
  lucene.grantingersoll.com/?p=112</guid>
  <description><![CDATA[Charlotte JUG 
  >> OCT 15TH - 6PM - Search and Text Analysis
I will be speaking at the Charlotte Java Users 
Group on Oct. 15th, covering things
like Lucene, Solr, OpenNLP and Mahout, amongst other things.
]]></description>
</item>
</channel>

Кстати говоря, каждая запись в базе данных содержит URL статьи ленты, оценку (выставленную мной случайным образом) и дату редактирования. Далее необходимо отобразить эту структуру в Solr. Это делается при помощи сущностей, поэтому мы подробно рассмотрим каждую строку их описания в файле rss-data-config.xml, показанном в листинге 9 (номера и переводы строк сделаны в целях повышения читабельности).

Листинг 9. Объявление сущности
1. <entity name="solrFeed"
2.pk="link"
3.url="http://lucene.grantingersoll.com/category/solr/feed"
4.processor="XPathEntityProcessor"
5.forEach="/rss/channel | /rss/channel/item"
6.            dataSource="rss"
7.        transformer="DateFormatTransformer">
8.  <field column="source" xpath="/rss/channel/title"
        commonField="true" />
9.  <field column="source-link" xpath="/rss/channel/link"
        commonField="true" />
10.  <field column="title" xpath="/rss/channel/item/title" />
11.  <field column="link" xpath="/rss/channel/item/link" />
12.  <field column="description"
        xpath="/rss/channel/item/description" />
13.  <field column="category" xpath=
"/rss/channel/item/category" />
14.  <field column="content" xpath=
"/rss/channel/item/content" />
15.  <field column="date" xpath="/rss/channel/item/pubDate"
        dateTimeFormat="EEE, dd MMM yyyy HH:mm:ss Z" />
16.  <entity name="rating" pk="feed"
      query="select rating from feeds where feed = '${solrFeed.link}'"
17.   deltaQuery="select rating from feeds where feed = '${solrFeed.link}'
            AND last_modified > '${dataimporter.last_index_time}'"
18.          dataSource="ratings"
19.          >
20.    <field column="rating" name="rating"/>
21.  </entity>
22. </entity>
  • строка 1: имя сущности (solrFeed);
  • строка 2: первичный ключ элемента. Это необязательный параметр, он используется только в процессе дельта-импорта;
  • строка 3: URL статьи, в данном случае – моей записи в блоге, посвященной Solr;
  • строка 4: EntityProcessor, использующийся для преобразования данных, поступающих из источника;
  • строка 5: выражение XPath для извлечения записей из XML. При помощи XPath можно задавать пути к конкретным элементам и атрибутам в XML. Если вы не знакомы с XPath, то обратитесь к источникам информации в разделе Ресурсы;
  • строка 6: имя использующегося источника данных (DataSource);
  • строка 7: класс DateFormatTransformer, использующийся для преобразования строк в экземпляры java.util.Date;
  • строка 8: связывает заголовок ленты (имя записи в блоге) с полем source в схеме Solr. Этот параметр задается один раз для всей ленты, поэтому в атрибуте commonField указывается, что его значение должно использоваться для каждого элемента;
  • строки 9 - 14: связывают различные части RSS-ленты с полями документов;
  • строка 15: связывает дату публикации с полем Solr, предварительно преобразовав ее в экземпляр java.util.Date при помощи DateFormatTransformer;
  • строки 16 - 21: описывают дочернюю сущность, представляющую собой оценки каждой статьи в базе данных;
  • строка 16: в атрибуте query указывается SQL-запрос для получения оценок. Вместо параметра ${solrFeed.link} во время выполнения запроса подставляется URL каждой статьи;
  • строка 17: задает текст запроса для дельта-импорта. Значение параметра ${dataimporter.last_index_time} устанавливается DIH;
  • строка 18: имя источника данных JDBC;
  • строка 20: связывает имя колонки в базе данных, в которой хранятся оценки, с полем в Solr. Если атрибут name не указан, то по умолчанию используется имя колонки.

Далее выполним импорт данных. Это можно сделать при помощи следующего HTTP-запроса:

http://localhost:8983/solr/rss/dataimport?command=full-import

В результате этого запроса из индекса сначала будут удалены все существующие документы, а затем будет произведен полный импорт данных. Будьте аккуратны: индекс сначала будет полностью очищен. Состояние DIH можно опросить в любое время, обратившись по URL http://localhost:8983/solr/rss/dataimport. В данном примере ответ DIH будет выглядеть примерно так, как показано в листинге 10.

Листинг 10. Результаты импорта
<response>
<lst name="responseHeader">
 <int name="status">0</int>
 <int name="QTime">0</int>
</lst>
<lst name="initArgs">
 <lst name="defaults">
  <str name="config">rss-data-config.xml</str>
 </lst>
</lst>
<str name="status">idle</str>
<str name="importResponse"/>
<lst name="statusMessages">
 <str name="Total Requests made to
  DataSource">11</str>
 <str name="Total Rows Fetched">13</str>
 <str name="Total Documents Skipped">0</str>
 <str name="Full Dump Started">2008-10-03 10:51:07</str>
 <str name="">Indexing completed.
  Added/Updated: 10 documents.
  Deleted 0 documents.</str>
 <str name="Committed">2008-10-03 10:51:18</str>
 <str name="Optimized">2008-10-03 10:51:18</str>
 <str name="Time taken ">0:0:11.50</str>
</lst>
<str name="WARNING">This response format is experimental.  It is
  likely to change in the future.</str>
</response>

Дельта-импорт данных

Если в качестве источника информации используется база данных, то можно импортировать только те записи, которые были изменены с момента последнего полного импорта. Это операция называется дельта-импортом (delta-import). К сожалению, в случае RSS эта функциональность пока недоступна, в противном случае URL соответствующего запроса выглядел бы примерно так:
http://localhost:8983/solr/rss/dataimport?command=delta-import


Не исключено, что к моменту прочтения этой статьи индекс будет содержать больше документов, так как я, скорее всего, добавлю несколько статей о Solr в блог. После индексирования можно опрашивать состояние индекса по адресу http://localhost:8983/solr/rss/select/?q=*%3A*&version=2.2&start=0&rows=10&indent=on. В результате мы получим все 10 проиндексированных документов.

Пока этого достаточно для первого знакомства с DIH. Далее, по мере изучения, вы, скорее всего, заинтересуетесь тем, как работает механизм подстановки значений переменных, а также вопросами создания собственных преобразователей (Transformer). Эти аспекты работы с DIH представлены на странице wiki, посвященной DataImportHandler (ссылка приведена в разделе Ресурсы). Мы же перейдем к вопросам поиска схожих страниц при помощи компонента MoreLikeThisComponent.

Поиск схожих страниц

Компонент MoreLikeThisComponent и схема Solr

Для реализации механизма поиска схожих страниц (More Like This – MLT) необходимо, чтобы поля либо хранились в виде массивов терминов либо использовали эти массивы. Подобные массивы хранят информацию в документо-ориентированном виде. Компонент, реализующий MLT, анализирует содержимое документа для составления списка наиболее важных терминов. Затем он строит запрос на основе исходных параметров и данных терминов, получая тем самым дополнительные результаты. Эти действия можно выполнять значительно эффективнее при помощи массивов терминов. Все, что необходимо – это добавить атрибут termVectors="true" в объявление поля в файле schema.xml.

Выполнив поиск в Google, вы, скорее всего, обнаружите рядом с каждой найденной страницей ссылку "похожие страницы" (similar pages). При ее нажатии будет выполнен еще один поиск, в результате которого будут найдены документы, похожие на изначальные страницы. В Solr подобная функциональность реализуется компонентом MoreLikeThisComponent (MLT) и обработчиком MoreLikeThisHandler. MLT интегрирован в стандартные обработчики SolrRequestHandler по описанным выше принципам. Обработчик MoreLikeThisHandler не только включает в себя MLT, добавляя поддержку дополнительных параметров, но и требует выполнение еще одного запроса. Далее мы подробно рассмотрим компонент MLT, поскольку именно его вам, скорее всего, придется использовать. К счастью, для него не нужна дополнительная настройка, все что требуется – это просто выполнять запросы.

В HTTP-запросах можно использовать огромное число параметров, однако для большинства из них есть подходящие во многих случаях значения по умолчанию. Вследствие этого мы остановимся только на тех параметрах, которые необходимы для работы с MLT (таблица 2). Более подробная информация приведена на wiki-странице MLT, ссылка на которую содержится в разделе Ресурсы.

Таблица 2. Параметры компонента MoreLikeThisComponent
alt-rowalt-row
ПараметрОписаниеДиапазон значений
mltВключение/выключение компонента MoreLikeThisComponent при выполнении запросаtrue|false
mlt.countНеобязательный параметр. Число схожих документов, запрашиваемых для каждого результата.> 0
mlt.flПоля, используемые для формирования MLT-запроса.Любое поле схемы, содержащее или хранящееся в виде массива терминов.
mlt.maxqtНеобязательный параметр. Максимальное число слов для поиска. Объемные документы могут содержать множество важных ключевых слов, поэтому сформированные MLT-запросы могут оказаться очень длинными и ухудшать быстродействие. В некоторых случаях возможно даже возникновение пугающего исключения TooManyClausesException. Этот параметр позволяет избежать этого, оставляя только наиболее важные ключевые слова.> 0

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

http://localhost:8983/solr/rss/select/?q=*%3A*&start=0&rows=10&mlt=true
  &mlt.fl=description&mlt.count=3
http://localhost:8983/solr/rss/select/?q=solr&version=2.2&start=0&rows=10
  &indent=on&mlt=true&mlt.fl=description&mlt.fl=title&mlt.count=3

Далее рассмотрим функцию "Вы имели в виду?", т.е. проверку орфографии.

Орфографические подсказки

Функции проверки орфографии появились в Lucene и Solr достаточно давно, однако до появления архитектуры на основе компонент (SearchComponent) их было не так просто использовать. Теперь же можно не просто получать результаты запроса, но и проверять написание терминов в нем, выдавая при необходимости подсказки (варианты корректировки опечаток). Подобные подсказки могут использоваться аналогично функциям "Вы имели в виду?" (Did you mean?) в Google или "Также попробуйте..." (Also Try) в Yahoo!.

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

В отличие от MLT, компонент SpellCheckComponent необходимо конфигурировать в файлах solrconfig.xml и schema.xml. Первым и основным конфигурационным параметром является объявление поля и ассоциированного с ним типа (FieldType), содержимое которого будет использоваться в качестве словаря для проверки орфографии. Как правило, анализ этого поля должен быть достаточно простым и не включать сложных алгоритмов, например, для выделения основ слов и других модификаций токенов. В нашем примере в FieldType содержится один элемент <analyzer>, показанный в листинге 11.

Листинг 11. Пример объявления <analyzer>
<fieldType name="textSpell" class="solr.TextField" positionIncrementGap="100" >
  <analyzer>
    <tokenizer class="solr.StandardTokenizerFactory"/>
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
  </analyzer>
</fieldType>

Этот анализатор выполняет базовое разбиение строк на токены (фактически просто разделяет строку по пробелам), затем переводит все символы в нижний регистр и удаляет дубликаты. Он не делает ничего сложного, в частности, ни выделения основ, ни вставки синонимов. Далее в файле schema.xml объявляется поле с именем spell, типом которого (<fieldType>) является описанный выше тип textSpell. Еще ниже объявляется компонент (элемент <searchComponent>), который использует конфигурационные параметры, определенные в файле solrconfig.xml (листинг 12).

Листинг 12. Пример объявления <searchComponent>
<searchComponent name="spellcheck" class="solr.SpellCheckComponent">
    <str name="queryAnalyzerFieldType">textSpell</str>
    <lst name="spellchecker">
      <str name="name">default</str>
      <str name="field">spell</str>
      <str name="spellcheckIndexDir">./spellcheckerDefault</str>
    </lst>
</searchComponent>

В этом примере ранее объявленному типу поля textSpell присваивается имя queryAnalyzerFieldType (обратите внимание, что компонент добавляется в конец цепочки из Dismax и стандартных объявлений SolrRequestHandler в файле solrconfig.xml). Это гарантирует, что входящие запросы будут корректно проанализированы, т.е. будет выполняться сравнение с написаниями токенов в индексе. Оставшиеся конфигурационные параметры задают имя компонента, проверяющего орфографию, поле, содержимое которого будет использоваться для построения индекса, а также местоположение индекса на диске.

Закончив с настройкой, необходимо построить орфографический индекс. Для этого достаточно отправить следующий HTTP-запрос данному компоненту:

http://localhost:8983/solr/rss/select/?q=foo&spellcheck=true&spellcheck.build=true

Процесс построения орфографического индекса

Данный индекс необходимо построить перед его использованием. Перед первоначальным созданием индекса следует указать, как часто он должен обновляться. В частности, можно перестраивать индекс после каждой операции commit, зарегистрировав объект-слушателя события postCommit в файле solrconfig.xml. Частота обновления индекса должна зависеть от того, насколько интенсивно он меняется, хотя это не критично в случаях, когда серьезные изменения не затрагивали словарь с момента первоначального создания индекса.

После того как индекс построен, можно выполнять поиск с подсказками. Для этого достаточно добавить параметр spellcheck=true в запрос. Пример приведен в листинге 13.

Листинг 13. Запрос, иллюстрирующий проверку орфографии
http://localhost:8983/solr/rss/select/?q=holr&spellcheck=true

Несмотря на то, что этот запрос не возвращает никаких результатов, он выдает следующие подсказки:

<lst name="spellcheck">
 <lst name="suggestions">
  <lst name="holr">
	<int name="numFound">1</int>
	<int name="startOffset">0</int>

	<int name="endOffset">4</int>
	<arr name="suggestion">
	 <str>solr</str>
	</arr>
  </lst>
 </lst>
</lst>

Орфографические подсказки также могут предоставляться в случае запросов по нескольким ключевым словам; более того, компонент даже способен автоматически предлагать новый запрос, в котором сочетаются наилучшие подсказки для каждого слова. Для этого в запросе надо указать параметр spellcheck.collate=true.

http://localhost:8983/solr/rss/select/?q=holr+foo&spellcheck=true&indent=on
&spellcheck.collate=true

В результате будет получена подсказка <str name="collation">solr for</str>. При этом обратите внимание, что данный запрос может не вернуть результатов вообще. Это зависит от того, объединяются ключевые слова по принципу логического "И" или нет.

Компонент проверки орфографии также поддерживает другие параметры, которые, в частности, могут влиять на число выдаваемых подсказок и качество результатов. Больше информации на тему SpellCheckComponent можно найти на wiki-странице Solr (ссылка приведена в разделе Ресурсы).

Далее мы рассмотрим возможности влияния на выдаваемые результаты при помощи так называемого "платного размещения".

Размещение редакторских результатов

В идеальном мире поисковая система всегда выдает только актуальные результаты в ответ на любые запросы. В реальности же редакторы (за неимением лучшего термина будем использовать "редакторы") часто явно указывают, что конкретные документы должны выдаваться в определенном месте среди результатов определенных запросов. Это может происходить по ряду причин. Во-первых, подобный документ в действительности может быть наиболее актуальным результатом. Во-вторых, возможно, ваша компания хочет, чтобы клиенты сначала видели наиболее прибыльные для нее продукты. Наконец, третья сторона может просто платить за то, чтобы результаты некоторых запросов выдавались в определенном порядке. Как бы то ни было, зачастую очень сложно (или даже невозможно) гарантировать, что указанный документ окажется в заданной позиции среди результатов определенного запроса, используя только естественный механизм ранжирования. Более того, даже если поисковая система сможет обеспечить нужные результаты для одного запроса, есть вероятность, что другие станут обрабатываться некорректно. Из этого можно сделать один вывод, имеющий фундаментальное значение для поиска информации в реальном мире: обработка запроса необязательно должна включать реальное сканирование индекса и ранжирование документов. Возможно, вам покажется странным слышать эти слова от человека, профессионально занимающегося поисковыми системами, однако задумайтесь об этом. Не исключено, что можно кэшировать типичные запросы и просто выдавать нужные результаты при их повторе (в Solr поддерживается такая возможность). Кроме того, иногда приходится жестко задавать результаты для запросов по перечисленным выше причинам.

В Solr редактирование результатов реализуется компонентом с загадочным именем QueryElevationComponent. В листинге 14 показаны его конфигурационные настройки для использования в демонстрационном приложении.

Листинг 14. Объявление компонента QueryElevationComponent
<searchComponent name="elevator"
  class="org.apache.solr.handler.component.QueryElevationComponent"
  >
    <!-- указание типа поля для анализа запросов -->
    <str name="queryFieldType">string</str>
    <str name="config-file">elevate.xml</str>
  </searchComponent>

При помощи атрибута queryFieldType указывается, каким образом распознавать запросы, для которых надо выдавать предустановленные результаты. Тип поля string говорит о том, что это делается простым сравнением строк (текста запроса) без какого бы то ни было анализа. В атрибуте config-file задается имя файла, в котором хранятся запросы и соответствующие результаты. Они размещаются в отдельном файле, чтобы его можно было редактировать вне Solr. Сам файл должен находиться в подкаталоге conf или data в главной директории Solr. В последнем случае он будет читаться сервером каждый раз при перезагрузке индекса.

В демонстрационном приложении используется файл elevate.xml в каталоге conf. Он содержит запись, соответствующую запросу "Solr", и три записи, соответствующие результатам (листинг 15).

Листинг 15. Sample elevate.xml configuration
<query text="Solr">
<doc
 id="http://lucene.grantingersoll.com/2008/06/21/solr-spell-checking-addition/"/>
<doc
  <!-- Перевод строки сделан исключительно в целях удобства чтения -->
 id="http://lucene.grantingersoll.com/2008/10/01/\
      charlotte-jug-%c2%bb-oct-15th-6pm-search-and-text-analysis/"
          />
<doc
 id="http://lucene.grantingersoll.com/2008/08/27/solr-logo-contest/" exclude="true"/>
</query>

Из листинга 15 следует, что первый документ всегда будет выдан перед вторым, а третий и вовсе будет исключен. Остальные результаты будут выдаваться в естественном порядке. Если вы хотите получать только естественные результаты, то выполните следующий запрос (редактирование включено по умолчанию при наличии этого компонента):

http://localhost:8983/solr/rss/select/?q=Solr&version=2.2&start=0&rows=10&indent=on
  &fl=link&enableElevation=false

Для получения отредактированных результатов выполните запрос, показанный ниже.

http://localhost:8983/solr/rss/select/?q=Solr&version=2.2&start=0&rows=10&indent=on
  &fl=link&enableElevation=true

Вы должны увидеть влияние редактирования на результаты запроса.

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

SolrJ

В статьях серии Умный поиск при помощи Apache Solr рассказывалось об ухищрениях для создания простого клиентского приложения, которое использовало библиотеку Apache HTTPClient для взаимодействия с Solr через Java. Теперь Solr 1.3 предоставляет простой программный интерфейс Java, который скрывает все пугающие детали HTTP-соединений и команд XML. Этот клиент, получивший название SolrJ, значительно упрощает работу с Solr в Java. API SolrJ облегчает индексирование, поиск, сортировку и сегментирование благодаря продуманной системе методов.

Как и другие возможности Solr, лучше всего будет продемонстрировать SolrJ на простом примере. В архив с исходным кодом примеров включен файл SolrJExample.java (инструкции по компилированию находятся в README.txt), в котором осуществляется индексирование документов Solr, а также выполнение запроса с классификацией результатов. Вначале происходит установка соединения с сервером Solr: SolrServer server = new CommonsHttpSolrServer("http://localhost:8983/solr/rss");. В этой строчке создается экземпляр класса SolrServer, который берет на себя взаимодействие с Solr через HTTP. Далее создаются несколько экземпляров SolrInputDocument, которые играют роль оберток над индексируемым содержимым (листинг 16).

Листинг 16. Индексирование при помощи SolrJ
Collection<SolrInputDocument> docs = new HashSet<SolrInputDocument>();
for (int i = 0; i < 10; i++) {
  SolrInputDocument doc = new SolrInputDocument();
  doc.addField("link", "http://non-existent-url.foo/" + i + ".html");
  doc.addField("source", "Blog #" + i);
  doc.addField("source-link", "http://non-existent-url.foo/index.html");
  doc.addField("subject", "Subject: " + i);
  doc.addField("title", "Title: " + i);
  doc.addField("content", "This is the "
   + i + "(th|nd|rd) piece of content.");
  doc.addField("category", 
  CATEGORIES[rand.nextInt(CATEGORIES.length)]);
  doc.addField("rating", i);
  //System.out.println("Doc[" + i + "] is " + doc);
  docs.add(doc);
}

Цикл в листинге 16 состоит только лишь из создания экземпляров SolrInputDocument (фактически класса-обертки над Map) и добавления в него полей. Данные экземпляры помещаются в коллекцию, чтобы их все можно было передать Solr за один раз, тем самым увеличивая производительность индексирования и снижая накладные расходы на передачу данных по HTTP. Затем выполняется строка UpdateResponse response = server.add(docs);, в которой и заключается все волшебство, касающееся сериализации документов и пересылке их серверу Solr. Возвращаемое значение UpdateResponse содержит данные о времени, затраченном на обработку документов. Далее выполняется команда подтверждения (server.commit();), поскольку необходимо, чтобы переданные документы были доступны для поиска.

Разумеется, после того как все документы проиндексированы, логично выполнить поисковый запрос. Пример приведен в листинге 17.

Листинг 17. Выполнение запроса к серверу
//формирование запроса
SolrQuery query = new SolrQuery("content:piece");
//включение режима классификации результатов
query.setFacet(true);
//указание поля, по которому будет выполнена классификация
query.addFacetField("category");
//нас интересуют только те категории, в которых есть хотя бы одна запись
query.setFacetMinCount(1);
//выполнение запроса
QueryResponse results = server.query(query);
System.out.println("Query Results: " + results);
//печать категорий
List<FacetField> facets = results.getFacetFields();
for (FacetField facet : facets) {
  System.out.println("Facet:" + facet);
}

В этом простом примере сначала настраивается экземпляр SolrQuery, который будет выполнять запрос с именем content:piece. Далее указывается, что нам необходим вывод результатов по категориям (по всем, для которых найдена хотя бы одна запись). Наконец, запрос отправляется на сервер при помощи вызова server.query(query), после чего результаты печатаются в поток стандартного вывода. Несмотря на всю тривиальность примера, он демонстрирует типичные приемы работы с Solr и предоставляет пищу для размышлений на тему других потенциальных возможностей (например, подсветки результатов, сортировки и т.д.). Если вас интересует более подробная информация о параметрах, поддерживаемых SolrJ, то обратитесь по ссылкам, приведенным в разделе Ресурсы.

Масштабирование индексов и распределенный поиск

Предыдущие версии Solr были достаточно хорошо масштабируемы в смысле обслуживания большого числа запросов за счет репликации, однако была проблема с хранением индексов, размер которых был слишком велик для одного компьютера. В этом случае для достижения масштабируемости требовались усилия на прикладном уровне. Например, можно было сконфигурировать Solr таким образом, чтобы каждый индекс хранился на своем сервере, однако при этом управление поиском становилось обязанностью клиентского приложения и требовало немалого объема кода. В Solr 1.3 появились функции распределенного поиска. Теперь клиентскому приложению остается только разделить документы на части, которые будут храниться на нескольких машинах, которые в терминологии называются шардами (shard, сокращение от английского shared – общий). Каждый шард содержит свой собственный индекс. Solr занимается координацией запросов к индексам, которые распределены по нескольким шардам. К сожалению, в настоящий момент задача распределения документов по шардам для индексирования по-прежнему ложится на приложение, но, скорее всего, она станет стандартной функцией Solr в одном из будущих релизов. Пока же можно использовать простую хэш-функцию для определения шарда для каждого документа на основе идентификатора последнего. Далее мы будем рассматривать только сам процесс поиска.

Максимальный размер индекса Solr для одного компьютера

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

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

Рисунок 2. Архитектура распределенного поиска Solr с применением репликации
Sample search architecture

Проблемы, связанные с распределенным поиском

Подход к реализации распределенного поиска в Solr имеет несколько недостатков. Во-первых, главный узел не застрахован от отказов и, если с ним что-то случится, то вся система не сможет индексировать новые документы и выполнять репликацию. Это не должно нарушить работоспособность поиска и зачастую не является проблемой в небольших системах, в которых можно вручную управлять шардами при помощи скриптов или внешних средств мониторинга. Другими словами, Google на такой архитектуре не построить, но поддерживать большие индексы вполне реально. Во-вторых, не все компоненты SearchComponent, вошедшие в версию 1.3, поддерживают распределенный поиск. Его поддерживают компоненты, занимающиеся собственно поиском, а также классифицированием результатов, отладкой и подсветкой. Остальные компоненты используются не так часто, и над ними продолжается работа. Существует еще несколько мелких недостатков, но они не критичны (более полная информация содержится в wiki-страницах, ссылки на которые приведены в разделе Ресурсы).

Как видно из рисунка 2, входящие запросы могут быть перенаправлены на любой репликант, так как каждый из них представляет собой самостоятельный экземпляр Solr. Кроме того, принимающий узел может посылать запросы к другим шардам. Эти запросы ничем не отличаются от обыкновенных запросов в Solr. Для указания того, что сервер Solr может распределить запрос по другим узлам, применяется параметр shards (см. пример ниже).

http://localhost:8983/solr/select?
  shards=localhost:8983/solr,localhost:7574/solr&q=ipod+solr

В этом примере подразумевается, что оба сервера Solr запущены на локальном компьютере – один слушает порт 8983, а другой – 7574 (разумеется, такую архитектуру нельзя назвать распределенной, но для примера ее вполне хватит). Входящие запросы поступают на вход сервера, слушающего порт 8983, который затем посылает запросы шардам. Скорее всего, значения параметра shards заданы в конфигурационных настройках обработчика SolrRequestHandler в файле solrconfig.xml, поэтому имена шардов необязательно передавать в параметрах каждого запроса.


Что дальше?

Как видите, в версии 1.3 появилось очень много нового. В этой статье было рассказано о множестве новых возможностей Solr, в том числе о проверке орфографии, импорте данных, редактировании результатов, распределенном поиске, а также о таких усовершенствованиях, как использование новой, более быстрой версии Lucene. Многие аспекты Solr поменялись, но многое осталось неизменным. Он по-прежнему представляет собой надежный, конкурентоспособный и хорошо сопровождаемый поисковый сервер, готовый к использованию в корпоративных системах. В будущих версиях ожидаются такие новые функции, как кластеризация документов, более развитые средства анализа, удаление дубликатов документов, а также механизм репликаций, совместимый с Windows.


Загрузка

ОписаниеИмяРазмер
Демонстрационное приложениеj-solr-update.zip437 KБ

Ресурсы

Научиться

  • Оригинал статьи: What's new with Apache Solr (Грант Ингерсолл, developerWorks, ноябрь 2008 г.). (EN)
  • Посетите домашнюю страницу Solr, на которой содержатся путеводители и документация Javadoc. Кроме того, вы узнаете о новостях сообщества Solr. (EN)
  • Обратитесь к Wiki-страницам Solr. В них вы найдете много полезных документов, в том числе по следующим темам (EN):
    • CollectionDistribution: узнайте больше о репликации в Solr;
    • MoreLikeThis: прочитайте обо всех возможностях данного компонента;
    • SearchComponent: узнайте, как можно расширить поисковые возможности Solr;
    • подключаемые модули в Solr: ознакомьтесь с возможностями создания собственных расширений Solr;
    • DataImportHandler: прочитайте об использовании обработчика импорта данных;
    • SpellCheckComponent: прочитайте о функциях данного компонента, а также о других средствах Solr для проверки орфографии;
    • QueryElevationComponent: узнайте больше о редактировании результатов поиска в Solr;
    • SolrJ: получите всю необходимую информацию о клиенте SolrJ;
    • Distributed Search: ознакомьтесь со всеми преимуществами и недостатками реализации распределенного поиска в Solr.
  • Посетите домашнюю страницу Lucene – проекта, который достался по наследству Solr. (EN)
  • Ознакомьтесь с примечаниями к выпуску Apache Solr 1.3.0 – последней версии Solr. (EN)
  • Узнайте больше об XPath, прочитав материалы developerWorks. (EN)
  • Ознакомьтесь с алгоритмом Портера, который используется в Solr для выделения основ слов. (EN)
  • Прочитайте книгу Lucene в действии, издание 2-ое (Отис Господнетич, Otis Gospodnetic, Эрик Хэтчер, Erik Hatcher и Майк Маккэндлесс, Mike McCandless, Manning, выпуск намечен на апрель 2009 г., открыт предварительный доступ к отдельным главам). Эта книга – незаменимый источник информации для всех интересующихся Lucene. (EN)
  • Обратитесь к магазину технической литературы, в котором представлены книги на данную и другие темы. (EN)
  • Сотни статей по всем аспектам программирования на Java можно найти на сайте developerWorks, в разделе Технология Java.

Получить продукты и технологии

  • Загрузите Solr 1.3 с одного из зеркал Apache. (EN)
  • Загрузите PostgreSQL. (EN)
  • Загрузите Luke – удобное средство для просмотра содержимого индекса Lucene. Luke может помочь вам понять, что такое индекс, а также оказать помощь в ситуациях, когда запросы не работают по неизвестным причинам. (EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, Open source
ArticleID=500089
ArticleTitle=Новые возможности Apache Solr
publish-date=07122010