Lucene
The Apache Lucene — это свободная библиотека для высокоскоростного полнотекстового поиска, написанная на Java. Может быть использована для поиска в интернете и других областях компьютерной лингвистики (аналитическая философия).
Основные возможности
- Масштабируемая и высокоскоростная индексация
- свыше 95GB в час на современном оборудовании
- требуется малый объем RAM — «heap» всего 1MB
- размер индекса примерно 20-30 % от размера исходного текста
- Мощный, точный и эффективный поисковый алгоритм
- ранжированный поиск — лучшие результаты показываются первыми
- множество мощных типов запросов: запрос фразы, wildcard запросы, поиск интервалов и т. д.
- поиск основанный на «полях» (таких как, заголовок, автор, текст)
- возможность сортировать по различным полям
- multiple-index поиск с возможностью объединения результатов
- возможность одновременного поиска и обновления индекса
- кроссплатформное решение
- исходный код полностью написан на Java
- наличие портов на другие языки программирования
Порты на другие языки
Lucene портирована на другие языки программирования:
Ссылки
- The Apache Lucene
- Lucene API
- Lucene FAQ
- Формат файлов
- Как начать
- Синтаксис запросов
- Scoring
- Lucene Wiki
- Краткий курс на русском
- Solr-Lucene FAQ
Литература
- Erik Hatcher and Otis Gospodnetic, «Lucene in Action», Manning, ISBN 1-932394-28-1
Apache Commons BCEL • BSF • JCS Apache Lucene Lucene Java • Lucene4c • Lucy• Solr Apache DB Derby • Torque • DdlUtils • OJB • JDO Ask.com (Ask Jeeves, механизм Teoma) • Blekko • Cuil (закрыт) • DuckDuckGo • Exalead • Gigablast • Google • Bing (Live Search/MSN Search) • Yahoo! Search (Inktomi • AltaVista • Alltheweb) • Яндекс
AskNet.ru • Brainboost • Clusty • Dogpile • FarSEER • exactus.ru • Excite • HotBot • Info.com • Ixquick • Krozilo • Mamma • Metacrawler • MetaLib • Нигма • Myriad Search • SideStep • Surfwax • Turbo10 • WebCrawler • GlobalFileSearch
DataparkSearch • Egothor • Gonzui • Grub • Ht://dig • locust • Isearch • Lucene • Lemur Toolkit & Indri Search Engine • mnoGoSearch • Namazu • Nutch • OpenFTS • Sciencenet (научная, на технологии YaCy) • Wikia Search • Sphinx • SWISH-E • Terrier Search Engine • Xapian • YaCy • Zettair
AGAKIDS (Россия) • Ask Kids (Великобритания) • Frag Finn (Германия) • Kids AOL (США) • Kids Yahoo! (США) • Quintura Дети (Россия) • Семейный Яндекс (Россия) • Гогуль (Россия)
- Программное обеспечение по алфавиту
- Поисковые системы
- Свободные библиотеки программ
- Библиотеки C
- Библиотеки C++
- Модули Perl
- Библиотеки PHP
Wikimedia Foundation . 2010 .
Введение в Apache Lucene
Apache Lucene — это полнотекстовый поисковый движок, который можно использовать с различными языками программирования.
В этой статье мы попытаемся понять основные концепции библиотеки и создать простое приложение.
2. Настройка Мавена
Для начала давайте сначала добавим необходимые зависимости:
dependency> groupId>org.apache.lucenegroupId> artifactId>lucene-coreartifactId> version>7.1.0version> dependency>Последнюю версию можно найти здесь .
Также для разбора наших поисковых запросов нам понадобится:
dependency> groupId>org.apache.lucenegroupId> artifactId>lucene-queryparserartifactId> version>7.1.0version> dependency>Проверьте наличие последней версии здесь .
3. Основные концепции
3.1. Индексация
Проще говоря, Lucene использует «обратное индексирование» данных — вместо сопоставления страниц с ключевыми словами ключевые слова сопоставляются со страницами точно так же, как глоссарий в конце любой книги.
Это позволяет быстрее получать ответы при поиске, поскольку поиск выполняется по индексу, а не по тексту напрямую.
3.2. Документы
Здесь документ представляет собой набор полей, и каждое поле имеет связанное с ним значение.
Индексы обычно состоят из одного или нескольких документов, а результаты поиска представляют собой наборы наиболее подходящих документов.
Это не всегда простой текстовый документ, это также может быть таблица базы данных или коллекция.
3.3. Поля
Документы могут иметь данные поля, где поле обычно представляет собой ключ, содержащий значение данных:
title: Goodness of Tea body: Discussing goodness of drinking herbal tea.Обратите внимание, что здесь title и body являются полями, и их можно искать вместе или по отдельности.
3.4. Анализ
Анализ преобразует данный текст в более мелкие и точные единицы для облегчения поиска.
Текст проходит различные операции по извлечению ключевых слов, удалению общеупотребительных слов и знаков препинания, переводу слов в нижний регистр и т. д.
Для этого есть несколько встроенных анализаторов:
- StandardAnalyzer — анализирует на основе базовой грамматики, удаляет стоп-слова, такие как «a», «an» и т. д. Также преобразует в нижний регистр
- SimpleAnalyzer — разбивает текст на основе символов без букв и преобразует в нижний регистр.
- WhiteSpaceAnalyzer — разбивает текст на основе пробелов
Мы также можем использовать и настраивать больше анализаторов.
3.5. Идет поиск
После того, как индекс построен, мы можем искать этот индекс, используя Query и IndexSearcher. Результатом поиска обычно является набор результатов, содержащий извлеченные данные.
Обратите внимание, что IndexWritter отвечает за создание индекса, а IndexSearcher — за поиск в индексе.
3.6. Синтаксис запроса
Lucene предоставляет очень динамичный и простой в написании синтаксис запросов.
Чтобы найти свободный текст, мы просто использовали текстовую строку в качестве запроса.
Для поиска текста в определенном поле мы будем использовать:
fieldName:text eg: title:teatimestamp:[1509909322,1572981321]Мы также можем искать с помощью подстановочных знаков:
dri?nkбудет искать один символ вместо подстановочного знака «?»
ищет слова, начинающиеся с «d» и заканчивающиеся на «k», с несколькими символами между ними.
найдет слова, начинающиеся с «uni».
Мы также можем комбинировать эти запросы и создавать более сложные запросы. И включите логический оператор, такой как И, НЕ, ИЛИ:
title: "Tea in breakfast" AND "coffee"Подробнее о синтаксисе запросов здесь .
4. Простое приложение
Давайте создадим простое приложение и проиндексируем некоторые документы.
Во-первых, мы создадим индекс в памяти и добавим в него несколько документов:
... Directory memoryIndex = new RAMDirectory(); StandardAnalyzer analyzer = new StandardAnalyzer(); IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer); IndexWriter writter = new IndexWriter(memoryIndex, indexWriterConfig); Document document = new Document(); document.add(new TextField("title", title, Field.Store.YES)); document.add(new TextField("body", body, Field.Store.YES)); writter.addDocument(document); writter.close();Здесь мы создаем документ с TextField и добавляем их в индекс с помощью IndexWriter. Третий аргумент в конструкторе TextField указывает, должно ли также сохраняться значение поля.
Анализаторы используются для разделения данных или текста на куски, а затем отфильтровывают из них стоп-слова. Стоп-слова — это такие слова, как «а», «ам», «есть» и т. д. Они полностью зависят от данного языка.
Далее создадим поисковый запрос и поищем в индексе добавленный документ:
public ListDocument> searchIndex(String inField, String queryString) Query query = new QueryParser(inField, analyzer) .parse(queryString); IndexReader indexReader = DirectoryReader.open(memoryIndex); IndexSearcher searcher = new IndexSearcher(indexReader); TopDocs topDocs = searcher.search(query, 10); ListDocument> documents = new ArrayList>(); for (ScoreDoc scoreDoc : topDocs.scoreDocs) documents.add(searcher.doc(scoreDoc.doc)); > return documents; >В методе search() второй целочисленный аргумент указывает, сколько лучших результатов поиска он должен вернуть.
Теперь давайте проверим это:
@Test public void givenSearchQueryWhenFetchedDocumentThenCorrect() InMemoryLuceneIndex inMemoryLuceneIndex = new InMemoryLuceneIndex(new RAMDirectory(), new StandardAnalyzer()); inMemoryLuceneIndex.indexDocument("Hello world", "Some hello world"); ListDocument> documents = inMemoryLuceneIndex.searchIndex("body", "world"); assertEquals( "Hello world", documents.get(0).get("title")); >Здесь мы добавляем в индекс простой документ с двумя полями «заголовок» и «тело», а затем пытаемся найти его с помощью поискового запроса.
6. Запросы Lucene
Поскольку мы уже знакомы с основами индексации и поиска, давайте копнем немного глубже.
В предыдущих разделах мы рассмотрели базовый синтаксис запроса и то, как преобразовать его в экземпляр Query с помощью метода QueryParser.
Lucene также предоставляет различные конкретные реализации:
6.1. TermQuery
Термин — это базовая единица для поиска, содержащая имя поля вместе с текстом для поиска.
TermQuery — самый простой из всех запросов, состоящий из одного термина:
@Test public void givenTermQueryWhenFetchedDocumentThenCorrect() InMemoryLuceneIndex inMemoryLuceneIndex = new InMemoryLuceneIndex(new RAMDirectory(), new StandardAnalyzer()); inMemoryLuceneIndex.indexDocument("activity", "running in track"); inMemoryLuceneIndex.indexDocument("activity", "Cars are running on road"); Term term = new Term("body", "running"); Query query = new TermQuery(term); ListDocument> documents = inMemoryLuceneIndex.searchIndex(query); assertEquals(2, documents.size()); >6.2. ПрефиксЗапрос
Чтобы найти документ со словом «начинается с»:
@Test public void givenPrefixQueryWhenFetchedDocumentThenCorrect() InMemoryLuceneIndex inMemoryLuceneIndex = new InMemoryLuceneIndex(new RAMDirectory(), new StandardAnalyzer()); inMemoryLuceneIndex.indexDocument("article", "Lucene introduction"); inMemoryLuceneIndex.indexDocument("article", "Introduction to Lucene"); Term term = new Term("body", "intro"); Query query = new PrefixQuery(term); ListDocument> documents = inMemoryLuceneIndex.searchIndex(query); assertEquals(2, documents.size()); >6.3. Подстановочный знак
Как следует из названия, мы можем использовать подстановочные знаки «*» или «?». для поиска:
// . Term term = new Term("body", "intro*"); Query query = new WildcardQuery(term); // .6.4. Фразезапрос
Он используется для поиска последовательности текстов в документе:
// . inMemoryLuceneIndex.indexDocument( "quotes", "A rose by any other name would smell as sweet."); Query query = new PhraseQuery( 1, "body", new BytesRef("smell"), new BytesRef("sweet")); ListDocument> documents = inMemoryLuceneIndex.searchIndex(query); // .Обратите внимание, что первый аргумент конструктора PhraseQuery называется slop и представляет собой расстояние в количестве слов между сопоставляемыми терминами.
6.5. нечеткий запрос
Мы можем использовать это при поиске чего-то похожего, но не обязательно идентичного:
// . inMemoryLuceneIndex.indexDocument("article", "Halloween Festival"); inMemoryLuceneIndex.indexDocument("decoration", "Decorations for Halloween"); Term term = new Term("body", "hallowen"); Query query = new FuzzyQuery(term); ListDocument> documents = inMemoryLuceneIndex.searchIndex(query); // .Мы попытались найти текст «Хэллоуин», но с ошибкой в написании «хэллоуин».
6.6. логический запрос
Иногда нам может понадобиться выполнить сложный поиск, объединяя два или более разных типа запросов:
// . inMemoryLuceneIndex.indexDocument("Destination", "Las Vegas singapore car"); inMemoryLuceneIndex.indexDocument("Commutes in singapore", "Bus Car Bikes"); Term term1 = new Term("body", "singapore"); Term term2 = new Term("body", "car"); TermQuery query1 = new TermQuery(term1); TermQuery query2 = new TermQuery(term2); BooleanQuery booleanQuery = new BooleanQuery.Builder() .add(query1, BooleanClause.Occur.MUST) .add(query2, BooleanClause.Occur.MUST) .build(); // .7. Сортировка результатов поиска
Мы также можем сортировать документы результатов поиска по определенным полям:
@Test public void givenSortFieldWhenSortedThenCorrect() InMemoryLuceneIndex inMemoryLuceneIndex = new InMemoryLuceneIndex(new RAMDirectory(), new StandardAnalyzer()); inMemoryLuceneIndex.indexDocument("Ganges", "River in India"); inMemoryLuceneIndex.indexDocument("Mekong", "This river flows in south Asia"); inMemoryLuceneIndex.indexDocument("Amazon", "Rain forest river"); inMemoryLuceneIndex.indexDocument("Rhine", "Belongs to Europe"); inMemoryLuceneIndex.indexDocument("Nile", "Longest River"); Term term = new Term("body", "river"); Query query = new WildcardQuery(term); SortField sortField = new SortField("title", SortField.Type.STRING_VAL, false); Sort sortByTitle = new Sort(sortField); ListDocument> documents = inMemoryLuceneIndex.searchIndex(query, sortByTitle); assertEquals(4, documents.size()); assertEquals("Amazon", documents.get(0).getField("title").stringValue()); >Мы попытались отсортировать полученные документы по полям заголовков, которые являются названиями рек. Логический аргумент конструктора SortField предназначен для изменения порядка сортировки.
8. Удалить документы из индекса
Попробуем удалить некоторые документы из индекса на основе заданного Term:
// . IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer); IndexWriter writer = new IndexWriter(memoryIndex, indexWriterConfig); writer.deleteDocuments(term); // .Мы проверим это:
@Test public void whenDocumentDeletedThenCorrect() InMemoryLuceneIndex inMemoryLuceneIndex = new InMemoryLuceneIndex(new RAMDirectory(), new StandardAnalyzer()); inMemoryLuceneIndex.indexDocument("Ganges", "River in India"); inMemoryLuceneIndex.indexDocument("Mekong", "This river flows in south Asia"); Term term = new Term("title", "ganges"); inMemoryLuceneIndex.deleteDocument(term); Query query = new TermQuery(term); ListDocument> documents = inMemoryLuceneIndex.searchIndex(query); assertEquals(0, documents.size()); >9. Заключение
Эта статья была кратким введением в начало работы с Apache Lucene. Также мы выполнили различные запросы и отсортировали полученные документы.
Как всегда, код примеров можно найти на Github .
Exploring Java: Lucene
Lucene – это open-source библиотека для полнотекстового поиска. К сожалению, документация к нему не всегда хорошо организована, и новичку бывает сложно сориентироваться среди десятков новых понятий и названий. В этом посте я попробую немного исправить ситуацию, вкратце описав, что есть что в мире Lucene.
Apache Lucene и смежные проекты
Сам по себе Lucene – это Java-библиотека, однако если вы не пишите для JVM, не спешите закрывать статью. Во-первых, существует огромное количество портов этой библиотеки на другие языки программирования. В частности, для .NET есть class-per-class порт, который так и называется – Lucene.net. Во-вторых, если вы не хотите мучиться с тонкостями API, Apache предлагает готовый поисковый сервер – Solr. Если вы создаёте сайт на PHP и просто хотите добавить в него эффективный поиск а-ля Google, то вероятнее всего Solr – это именно то, что вам нужно. Нельзя не упомянуть и о самом «навороченном» проекте из ветки Lucene — Nutch. Этот проект представляет из себя синтез Solr и великого и ужасного Hadoop — распределённой файловой системы со встроенным MapReduce. Проще говоря, Nutch переносит возможности Solr’а с одного сервера на целый кластер, так что если ваша цель – создать мини-гугль, то вы попали по адресу. Тем более что кроме собственно поиска Nutch включает в себя свой собственный crawler и ряд парсеров для наиболее популярных форматов документов (HTML, PDF, DOC и др.). Так или иначе, все эти проекты построены вокруг одной архитектуры, имеют единый язык запросов и схожие компоненты. Обо всём этом и пойдёт речь далее.
Как работают поисковые движки
В Information Retrieval (IR) встречаются различные задачи, связанные с поиском по тексту, однако нас будет интересовать только одна – поиск наиболее релевантных документов по набору ключевых слов. Такой вид поиска обычно называют полнотекстовым. Важно понимать, что IR не сводится только к полнотекстовому поиску, и движки вроде Lucene могут оказаться бесполезны для других задач, таких задач, как, например, поиск подстроки в строке. Задача эффективного полнотекстового поиска делится на две части: индексирование и собственно поиск. Обе эти стадии мы ещё обсудим ниже, но вначале поговорим о том, что находится между ними – о хранилище. Хранилище в большинстве современных поисковых движков организовано в виде так называемого обратного индекса (inverted index). Обратный индекс организован аналогично предметному указателю в конце книги – каждому слову соответствует список документов, в которых он встречается (если быть более точным, список ID этих документов):

Такая структура позволяет практически за константное время извлекать список документов, в которых встречается определённое слово. Сам список слов организован в виде либо префиксного дерева, либо хеш-мэпа. Кроме собственно номеров документов для каждого слова сохраняется ряд атрибутов, таких как все позиции, на которых встречается данное слово в данном документе (необходимы для подсветки и создания сниппетов), сдвиги относительно предыдущего слова (для обработки синонимов), ряд других встроенных атрибутов, а также произвольный payload – набор байт, которые программист может использовать по своему усмотрению:

Хотя при стандартном сценарии программисту нет необходимости работать напрямую с обратным индексом, Lucene предоставляет доступ к нему через методы termDocs и termPositions класса IndexReader (подробнее об API ниже). Обычно под текстовым документом мы понимаем просто именованный текст. Однако в терминологии Lucene документ представляет собой нечто большее, а именно набор пар поле-значение, где текст документа является всего лишь значением одного из полей. Среди других полей могут быть заголовок, авторы, краткое описание и вообще что угодно, что может быть представлено в текстовом формате. Кроме того, значением поля может быть число, и в том числе дата. Это оказывается особо полезным в сочетании с возможностью Lucene’а искать по интервалу. Например, можно указать год издания статьи и затем найти все статьи в период между 2005 и 2010-м годами.

По сути, индекс Lucene представляет собой базу данных с объектами и полями этих объектов. Однако база эта – документно-ориентированная, а это значит, что в отличие от реляционных баз объекты в ней не обязаны подчиняться какой-либо схеме. Каждый документ может иметь сколько угодно каких угодно полей, независимо от того, какие поля имеют другие документы. Здесь же стоит отметить, что Lucene имеет один большой недостаток по сравнению с традиционными БД – он не создаёт ID для документов. Все документы внутри Lucene имеют свой номер, доступный извне, однако при удалении документа и оптимизации индекса Lucene может переставить номера. Поэтому если необходимо ввести уникальный идентификатор для каждого документа, то лучше добавить дополнительное поле и генерировать ID-шники самостоятельно.
Индексирование
Индексирование документов, таких как PDF-файлы, происходит в 2 этапа: вначале из них извлекается текст, а затем уже этот текст анализируется, и полученные данные попадают в поисковый индекс.
К сожалению, сам по себе Lucene, в отличие от Solr и Nutch, не умеет работать ни с PDF, ни с каким бы то ни было другим сложным форматом файлов. Для извлечения текста из таких файлов вам придётся использовать другие библиотеки. При поиске таких библиотек можно отталкиваться от соответствующих плагинов Nutch’а. При индексировании текста он проходит несколько стадий. Во-первых, текст разбивается на токены, то есть токенизируется (tokenizing). В простейшем случае разбиение происходит по пробелам и знакам препинания, однако это поведение может регулироваться. Во-вторых, каждый токен приводится к своей морфологической основе (stemming): обрезаются окончания, распространённые суффиксы заменяются на стандартную форму и т.д. Например, слово «questioning» из примера выше будет преобразовано в «question». В дальнейшем это позволит игнорировать при поиске форму слова, выдавая более точные результаты. Преобразование происходит на основе ряда простых логических правил и не всегда даёт правильный с точки зрения лингвистики результат, однако в большинстве случаев это не играет значительной роли. В-третьих, из списка токенов выбрасываются так называемые stop-words – наиболее распространённые, но не несущие особой смысловой нагрузки слова. Для английского языка это такие слова как “a», “the», “and» и т.д. В-четвёртых, каждому токену присваивается ряд атрибутов, часть из которых в дальнейшем попадает в индекс, а часть – используется на более поздних стадиях, но отбрасывается при сохранении в индекс. (На самом деле в последних версиях Lucene даже сам токен рассматривается просто как атрибут некоторого объекта.) В Lucene все эти стадии объединены в так называемых анализаторах. Выбор анализатора зависит от нескольких параметров, и в первую очередь от языка текста. Ветвь contrib из репозитория Lucene предоставляет довольно интересный анализатор – SnowballAnalyzer. В отличие от прочих анализаторов, SnowballAnalyzer не заточен ни на один конкретный язык, а принимает название языка в виде строки в своём конструкторе. В сочетании с автоматическим определителем языка из проекта Tika, он может оказаться прекрасным решением для многоязычных корпусов текстов. Среди других анализаторов стоит выделить KeywordAnalyzer, который индексирует всё анализируемое поле как единый токен. Это может быть полезно для таких полей как номер телефона, ID, различные коды и т.д.
Поиск
- title: Einstein
- content: The important thing is not to stop questioning.
- content: important
- content: is
- content: not
- content: questioning
- content: stop
- content: The
- content: thing
- content: to
- title: Einstein
API
- Analyzer, а также его потомки – отвечают за токенезацию, морфологические преобразования, фильтрация стоп-слов и т.д.
- TokenStream – представляет интерфейс для работы с потоком токенов. В последних версиях представляет их себя набор ленивых списков атрибутов, для чего наследуется от AttributeSource. Наследники же самого TokenStream делятся на две крупные группы, представленные классами Tokenizer и TokenFilter.
- Directory – интерфейс, отвечает за хранилище для индекса. Чаще всего используются две имплементации – FSDirectory для дискового индекса и RAMDirectory для индекса в памяти.
- Document – документ Lucene.
- Field – поле документа. В конструкторе принимает как минимум 4 параметра – имя поля, значение и два флага, отвечающие за хранение оригинального поля и за способ анализа.
- IndexWriter – класс, используемый для добавления документов в индекс, а также для их удаления.
- IndexReader – инкапсулирует весь функционал по чтению из индекса. Используется другими классами для поиска, предоставляет доступ к обратному индексу и многое другое.
- IndexSearcher – название говорит само за себя.
- Query – внутреннее представление запроса.
- QueryParser – то, что преобразует String в Query.
- TopScoreDocCollector и ScoreDoc – используются для сохранения и итерирования по результатам поиска.
Обзор решений для полнотекстового поиска в веб-проектах: Sphinx, Apache Lucene, Xapian
Любой разработчик, реализующий сегодня какой-либо проект, сталкивается с потребностью реализовать поиск в своём веб-приложении. Конечно, для каких-то проектов вполне подойдёт и простое решение, к примеру, от Google. Но чем более сложное приложение, и чем сложнее структура контента, если требуются особые виды поиска и обработки результата — тем большая потребность в собственной реализации. Но что же выбрать, какие сейчас на рынке есть поисковые проекты, которые готовы для использования в реальных проектах, не исследовательских или научных, а реальных приложениях? Далее мы кратко рассмотрим различные варианты поисковых решений, пригодных для встраивания или развёртывания на собственном сервере.
Общая архитектура и термины
Под поисковым сервером (или просто «поисковик») мы понимаем библиотеку или компонент, вообще, программное решение, которое самостоятельно ведёт свою базу данных (на самом деле это может быть и СУБД, и просто файлы и распределения платформа хранения) документов, в которых и происходит поиск. Поисковик также предоставляет сторонним приложениям возможность добавлять, удалять и обновлять документы в этой базе. Этот процесс называется индексированием, и может быть реализовано отдельным компонентом или сервером (индексатором). Другой компонент, поисковый механизм, принимает запрос на поиск и обрабатывая созданную базу, производит выборку данных, которые соответствуют запросу. Кроме этого, он может вычислять дополнительные параметры для результатов поиска (ранжировать документы, вычислять степень соответствия поисковому запросу и т. п.). Это самые важные системы поисковика, и они могут быть как монолитно реализованы в одной библиотеке, так и быть самостоятельными серверами, доступ к которым реализуется через различные прикладные протоколы и API.
Отдельно я бы выделил наличие модуля реализации веб-поиска. То есть, в поисковом сервере может быть реализована встроенная возможность получать документы с веб-сайтов по протоколу НТТР и заносить их в индекс. Этот модуль называется обычно «паук» или «crawler», и таким образом, поисковый сервер уже может быть похож на «настоящий» и привычный всем поиск вроде Google или Yandex. Так можно реализовать собственный поисковик по нужным вам сайтам, например, посвящённым одной теме — достаточно просто создать список адресов и настроить их периодических обход. Однако это уже задача гораздо более сложная и серьёзная, как технически, так и организационно, поэтому мы не останавливаемся на деталях её реализации. Среди проектов, которые мы рассмотрим, присутствует один сервер, именно реализующий веб-поисковик, то есть содержит все необходимое для создания «убийцы Яндекса». Интересно?
Какие параметры важны?
- скорость индексирования — то есть, как быстро поисковый сервер «перемалывает» документы и заносит их в свой индекс, делая доступным поиск по ним. Обычно измеряется в Мб чистого текста в секунду (обычно в тестах это 1U сервер, вроде 2 ГГц CPU и 1 Гб RAM + SATA диск или RAID).
- скорость переиндексации — в процессе работы документы изменяются или добавляются новые, поэтому приходится заново индексировать информацию. Если сервер поддерживает инкрементное индексирование, то мы обрабатываем только новые документы, а обновление всего индекса оставляем на потом или даже можем вообще не делать.
- поддерживаемые API — если вы используете поисковик в связке с веб-приложением, обратите внимание на наличие встроенного API к вашему языку или платформе.
- поддерживаемые протоколы — обычно поддерживаются или JSON-RPC, SOAP или доступ через http/socket.
- размер базы и скорость поиска — эти параметры очень взаимосвязаны и если вы реализуете что-то уникальное и предусматриваете, что у вас могут быть миллион и больше документов в базе, то посмотрите на известные реализации выбранной платформы. Хотя никто не заявляет явно про ограничения на количество документов в базах, и на небольших коллекциях (например, несколько десятков тысяч документов) все поисковики будут примерно одинаковые, но если речь идёт о миллионах документов — это может стать проблемой.
- поддерживаемые типы документов — конечно, любой сервер поддерживает обычный текст (хотя следует смотреть на возможность работы с многоязычными документами и кодировкой UTF-8), но если вам необходимо индексировать разные типы файлов, например, HTML, XML, DOC или PDF, то стоит посмотреть на те решения, где есть встроенный компонент для этого. Конечно, все это можно сделать прямо в вашем приложении, но лучше поискать готовые решения. Сюда же относится и поддержка индексирования и поиска информации, которая хранится в СУБД — не секрет, что такое хранение самое распространённое для веб-приложений, и лучше, чтобы поисковый сервер работал напрямую с базой данных.
- работа с разными языками и стемминг — для корректного поиска с использованием разных языков необходима родная поддержка не только кодировок, но и работа с особенностями языка. Все поддерживают английский язык, который для поиска и обработки достаточно простой. Модуль стемминга позволяет склонять и разбирать слова в поисковом запросе для более корректного поиска. Если для вас критичен поиск на русском языке, обратите внимание на присутствие этого модуля и его особенности.
- поддержка дополнительных типов полей в документах — кроме самого текста, который индексируется и в котором производится поиск, необходимо наличие возможности хранить в документе неограниченное количество других полей, которые хранят мета-информацию о документе, что необходимо для дальнейшей работы с результатами поиска. Очень желательно, чтобы количество и типы полей не ограничивались, а их индексируемость можно было настраивать. Например: в одном поле хранится название, во втором аннотация, в третьем ключевые слова, в четвёртом — идентификатор документа в вашей системе. Необходимо гибко настраивать область поиска (в каждом поле или только в указанных), а также те поля, которые будут извлекаться с базы поисковика и выдаваться с результатами поиска.
- платформа и язык — если вы собираетесь выделять поиск в отдельный от приложения модуль или сервер, или даже выносите его на отдельный сервер (железо в смысле), то роль платформы не такая и большая. Обычно это или C++ или Java.
- наличие встроенных механизмов ранжирования и сортировки — особенно хорошо, если поисковик можно расширять (и он написан на известном вам языке) и написать нужные вам реализации этих функций, ведь существует множество разных алгоритмов, и не факт, что используемый по умолчанию в поисковике вам подойдёт.
Теперь кратко расскажем о тех поисковых решениях, на которые вам следует обратить внимание, как только вы решите приступить к вопросу о поиске. Я намеренно не рассматриваю встроенные в вашу СУБД решение — FULLTEXT в MySQL и FTS в PostgreSQL. MySQL не может применяться для серьёзного поиска, особенно по большим объёмам данных, поиск в PostgreSQL намного лучше, но только если вы уже применяете эту базу. Хотя, как вариант — ставить отдельный сервер БД и там использовать только хранение данных и поиск тоже вариант.
Характеристики поисковых решений
Sphinx Apache Lucene Xapian Тип отдельный сервер или MySQL storage engine отдельный сервер или сервлет, встраиваемая библиотека встраиваемая библиотека Платформа
Индекс
Варианты поиска
API и протоколы
Поддержка языков
Дополнительные поля документов
Форматы
Размер индекса/скорость
Лицензия
URLSphinx search engine
Sphinx, вероятно, самый мощный и быстрый из всех открытых движков, которые мы рассматриваем. Особенно удобен тем, что имеет прямую интеграцию с популярными базами данных и поддерживает развитые возможности поиска, включая ранжирование и стемминг для русского и английского языка. Похоже, что отличную поддержку русского языка проект имеет из-за того, что автор — наш соотечественник, Андрей Аксенов. Поддерживаются и нетривиальные возможности вроде распределённого поиска и кластеризации, однако фирменной фичей является очень и очень высокая скорость индексации и поиска, а также способность отлично утилизировать ресурсы современных серверов. Известны очень серьёзные инсталляции, содержащие терабайты данных, поэтому Sphinx вполне можно рекомендовать как выделенный поисковый сервер для проектов любого уровня сложности и объёма данных. Прозрачная работа с самыми популярными базами данных MySQL и PostgreSQL позволяет его использовать в обычном для веб-разработки окружении, к тому же сразу «из коробки» есть API для разных языков, в первую очередь, для РНР. Но сам поисковик необходимо компилировать и устанавливать отдельно, поэтому на обычном хостинге он неприменим — только VDS или собственный сервер, причём желательно побольше памяти. Индекс у поисковика монолитный, поэтому придётся немного «извратиться», настраивая дельта-индекс для корректной работы в случае, когда очень много новых или изменённых документов, хотя огромная скорость индексации позволяет организовать перестройку индекса по расписанию и это не скажется на работе собственно поиска.
SphinxSE — это версия, функционирующая как движок хранения данных для MySQL (требует патча и перекомпиляции базы), Ultrasphinx — конфигуратор и клиент для Ruby (кроме присутствующего в дистрибутиве API), кроме этого есть плагины для многих известных CMS и блог-платформ, вики, которые заменяют стандартный поиск (полный список). Кстати, интересное обсуждение о выборе поисковика для Python веб-проекта.
Семейство Apache Lucene
Lucene — самый известный из поисковых движков, изначально ориентированный именно на встраивание в другие программы. В частности, его широко используют в Eclipse (поиск по документации) и даже в IBM (продукты из серии OmniFind). В плюсах проекта — развитые возможности поиска, хорошая система построения и хранения индекса, который может одновременно пополняться и оптимизироваться вместе с поиском. Доступен и параллельный поиск по множеству индексов с объединением результатов. Сам индекс построен из сегментов, однако для улучшения скорости рекомендуется его периодически оптимизировать. Изначально присутствуют варианты анализаторов для разных языков, включая русский с поддержкой стемминга (приведения слов к нормальной форме). Однако минусом является все же очень низкая скорость индексации (особенно в сравнении с Sphinx), сложность работы с базами данных и отсутствие API (кроме родного Java). И хотя для достижения серьёзных показателей Lucene может кластеризироваться и хранить индексы в распределённой файловой системе или базе данных, для этого требуется сторонние решения, так же как и для всех остальных функций — например, изначально он умеет индексировать только обычный текст. Но именно в плане использования в составе сторонних продуктов Lucene «впереди планеты всей» — ни один другой движок не имеет столько портов на другие языки. Одним из факторов такой популярности является и очень удачный формат файлов индексов, который используют сторонние решения.
Solr — лучшее решение на базе Lucene, значительно расширяющее её возможности. Это самостоятельный сервер корпоративного уровня, предоставляющий широкие поисковые возможности в качестве веб-сервиса. Стандартно Solr принимает документы по протоколу HTTP в формате XML и возвращает результат также через HTTP (XML, JSON или другой формат). Полностью поддерживается кластеризация и репликация на несколько серверов, расширена поддержка дополнительных полей в документах (в отличие от Lucene, для них поддерживаются различные стандартные типы данных, что приближает индекс к базам данных), поддержка фасетного поиска и фильтрации, развитые средства администрирования, а также возможности кеширования и бекапа индекса в процессе работы. С одной стороны, это самостоятельное решение на базе Lucene, с другой — её возможности существенно расширены относительно базовых, поэтому если вам необходим отдельный поисковый сервер, обратите сперва внимание на Solr.
Nutch — второй известнейший проект на базе Lucene. Это веб-поисковый движок (поисковый механизм + веб-паук для обхода сайтов) совмещённый с распределённой системой хранения данных Hadoop. Nutch «с коробки» может работать с удалёнными узлами в сети, индексирует не только HTML, но и MS Word, PDF, RSS, PowerPoint и даже MP3 файлы (мета-теги, конечно), по сути — это полноценный поисковик-убийца Google. Шучу, расплата за это — значительное урезание функционала Lucene, например не поддерживаются булевые операторы в поиске, не используется стемминг. Если стоит задача сделать небольшой локальный поисковик по местным ресурсам или заранее ограниченному набору сайтов, при этом нужен полный контроль над всеми аспектами поиска, или вы создаёте исследовательский проект для проверки новых алгоритмов, в таком случае Nutch станет вашим лучшим выбором. Однако учтите его требования к аппаратной части и широком канале — для реального web-поисковика счёт трафика идёт на терабайты.
Вы думаете, никто Nutch не использует «по-взрослому»? Ошибаетесь — из самых известных проектов, о которых вы могли слышать, его использует поисковая система по исходным кодам Krugle.
Но не только за счёт проектов-надстроек известен и популярен Lucene. Будучи лидером среди открытых решений и воплотив в себя множество отличных алгоритмов, Lucene первый кандидат в портирование на другие платформы и языки. Сейчас имеются следующие порты (я имею ввиду те, что более-менее активно развиваются и максимально полные):
- Lucene. Net — полный порт Lucene, полностью алгоритмически, по классах и API идентичный перенос на платформу MS. NET/Mono и язык C#.
- Ferret — порт на язык Ruby
- CLucene — версия на языке С++, что обещает дать существенный прирост производительности. По некоторым тестам, он быстрее оригинала в а иногда и более (на индексации, поиск сравним или быстрее на всего Оказалось, что эту версию использует большое количество проектов и компаний — ht://Dig, Flock, Kat (поисковик для KDE), BitWeaver CMS и даже такие компании, как Adobe (поиск по документации) и Nero.
- Plucene — реализация на Perl
- PyLucene — реализация для Python-приложений, однако не полная и требует java
- Zend_Search_Lucene — единственный порт на язык РНР, доступный в составе Zend Framework.
Xapian
Xapian пока это единственный претендент на конкуренцию Lucene и Sphinx, выгодно отличается от них наличием «живого» индекса, не требующего перестройки при добавлении документов, очень мощным языком запросов, включая встроенный стемминг, проверку орфографии, и даже поддержку синонимов. Однако я не нашёл никакой информации о возможности добавлять к документам произвольные дополнительные поля и получать их с результатами поиска, поэтому связь системы поиска с вашей собственной может представлять определённые трудности. В пакет входит Omega — надстройка над библиотекой, которая готова для использования в качестве самостоятельного поисковика и как раз она отвечает за возможности индексации разных типов документов и CGI интерфейс.
Наверное, на этом наш обзор можно завершить. Хотя существует ещё множество поисковых механизмов, на поверку часть из них является портами или надстройками над уже рассмотренными. Например, промышленного уровня поисковый сервер для собственной CMS компании eZ, ezFind на самом деле не отдельный поисковик, а интерфейс к стандартному Lucene Java и включает его в свою поставку. Это же касается и компонента Search из их пакета eZ Components — он предоставляет унифицированный интерфейс для доступа к внешним поисковым серверам. И даже такое интересное и мощное решение, как Carrot и SearchBox это серьёзно модифицированные версии той же Lucene, значительно расширенные и дополненные новыми возможностями. Самостоятельных же поисковых решений, с открытым кодом, которые полностью реализуют индексацию и поиск по собственных алгоритмах на рынке не так и много.
Выводы
Хотя окончательно принять решение, подходит или нет конкретный поисковик вашему проекту сможете только вы и, часто, лишь после детального исследования и тестов, однако некоторые выводы можно сделать уже сейчас.
Sphinx подойдёт вам, если необходимо индексировать большие объёмы данных в базе MySQL и вам важна скорость индексации и поиска, однако не требуются специфические возможности поиска вроде «fuzzy search» и вы согласны выделить на это отдельный сервер или даже кластер.
Если необходимо встроить поисковый модуль в ваше приложение, то лучше всего поиска готовые порты для вашего языка к библиотеке Lucene — для всех распространённых языков они есть, однако могут реализовывать далеко не все возможности оригинала. Если же вы разрабатываете приложение на Java, то Lucene однозначно лучший выбор. Однако учтите достаточную медленную индексации и необходимость частой оптимизации индекса (и требовательность к CPU и скорости диска). Для РНР это, по всей видимости, единственный приемлемый вариант полной реализации поиска без дополнительных модулей и расширений.
Xapian достаточно хороший и качественный продукт, однако менее распространённый и гибкий, чем остальные. Для приложений на С++ и требованиями к широким возможностям языка запроса он будет лучшим выбором, однако требует ручной доводки и модификаций для встраивания в собственный код или использования как отдельного поискового сервера.
Подобається Сподобалось 0
До обраного В обраному 0