Зачем нужен Lucene?
Поиск - одна из самых распространенных операций, которые мы выполняем несколько раз в день. Этот поиск может осуществляться по нескольким веб-страницам, которые существуют в Интернете, или в музыкальном приложении, или в репозитории кода, или по комбинации всего вышеперечисленного. Можно подумать, что простая реляционная база данных также может поддерживать поиск. Это правильно. Базы данных, такие как MySQL, поддерживают полнотекстовый поиск. Но как насчет Интернета, музыкального приложения, репозитория кода или комбинации всего вышеперечисленного?? База данных не может хранить эти данные в своих столбцах. Даже если бы это было так, на выполнение такого большого поиска потребуется неприемлемо много времени.
Система полнотекстового поиска способна выполнять поисковый запрос сразу по миллионам файлов. Скорость, с которой данные хранятся в приложении сегодня, огромна. Выполнение полнотекстового поиска в таком объеме данных - сложная задача. Это связано с тем, что нужная нам информация может находиться в одном файле из миллиардов файлов, хранящихся в сети.
Как работает Lucene?
Возникает очевидный вопрос: как Lucene так быстро выполняет полнотекстовые поисковые запросы?? Ответ на это, конечно же, с помощью индексов, которые он создает. Но вместо создания классического индекса Lucene использует Инвертированные индексы.
В классическом указателе для каждого документа мы собираем полный список слов или терминов, содержащихся в документе. В перевернутом указателе для каждого слова во всех документах мы сохраняем, какой документ и позицию, по которой можно найти это слово / термин. Это высококлассный алгоритм, который упрощает поиск. Рассмотрим следующий пример создания классического индекса:
Doc1 -> "This", "is", "simple", "Lucene", "sample", "classic", "инвертированный", "index"Doc2 -> "Запуск", "Elasticsearch", "Ubuntu", "Обновление"
Doc3 -> "RabbitMQ", "Lucene", "Kafka", "", "Spring", "Boot"
Если мы используем инвертированный индекс, у нас будут такие индексы, как:
Это -> (2, 71)Люцен -> (1, 9), (12,87)
Apache -> (12, 91)
Каркас -> (32, 11)
Инвертированные индексы намного проще поддерживать. Предположим, что если мы хотим найти Apache в моих условиях, я сразу получу ответы с инвертированными индексами, тогда как при классическом поиске будут выполняться полные документы, которые, возможно, было невозможно запустить в сценариях в реальном времени.
Рабочий процесс Lucene
Прежде чем Lucene сможет действительно искать данные, ей необходимо выполнить шаги. Давайте визуализируем эти шаги для лучшего понимания:
Рабочий процесс Lucene
Как показано на диаграмме, в Lucene происходит следующее:
- Lucene загружает документы и другие источники данных
- Для каждого документа Lucene сначала преобразует эти данные в обычный текст, а затем анализаторы преобразуют этот источник в обычный текст
- Для каждого термина в простом тексте создаются инвертированные индексы
- Индексы готовы к поиску
Благодаря этому рабочему процессу Lucene представляет собой очень сильную систему полнотекстового поиска. Но это единственная часть, которую выполняет Lucene. Нам нужно выполнять работу самим. Давайте посмотрим на необходимые компоненты индексирования.
Компоненты Lucene
В этом разделе мы опишем базовые компоненты и базовые классы Lucene, используемые для создания индексов:
- Справочники: Индекс Lucene хранит данные в обычных каталогах файловой системы или в памяти, если вам нужна более высокая производительность. Это полностью выбор приложений для хранения данных где угодно, в базе данных, оперативной памяти или на диске.
- Документы: Данные, которые мы передаем в движок Lucene, необходимо преобразовать в обычный текст. Для этого мы создаем объект Document, который представляет этот источник данных. Позже, когда мы запустим поисковый запрос, в результате мы получим список объектов Document, удовлетворяющих переданному нами запросу.
- Поля: Документы заполняются коллекцией полей. Поле - это просто пара (имя, значение) Предметы. Итак, при создании нового объекта документа нам нужно заполнить его такими парными данными. Когда поле инвертировано, значение поля токенизируется и доступно для поиска. Теперь, когда мы используем поля, важно хранить не фактическую пару, а только перевернутую проиндексированную. Таким образом, мы можем решить, какие данные доступны только для поиска и не важны для сохранения. Давайте посмотрим на пример здесь:
Индексирование полей
В приведенной выше таблице мы решили сохранить одни поля, а другие не сохраняются. Поле тела не сохраняется, а индексируется. Это означает, что электронное письмо будет возвращено в результате, когда будет выполнен запрос одного из Условий для содержимого тела.
- Условия: Термины представляют собой слово из текста. Термины извлекаются из анализа и токенизации значений полей, таким образом Срок - это наименьшая единица, по которой выполняется поиск.
- Анализаторы: Анализатор - самая важная часть процесса индексирования и поиска. Это анализатор, который преобразует открытый текст в токены и термины, чтобы их можно было искать. Что ж, это не единственная обязанность анализатора. Анализатор использует токенизатор для создания токенов. Анализатор также выполняет следующие задачи:
- Stemming: Анализатор преобразует слово в Stemming. Это означает, что слово «цветы» преобразуется в основное слово «цветок». Таким образом, при поиске по запросу "цветок" документ будет возвращен.
- Фильтрация: Анализатор также фильтрует такие стоп-слова, как «The», «is» и т. Д. поскольку эти слова не привлекают никаких запросов и не продуктивны.
- Нормализация: этот процесс удаляет акценты и другие символы символов.
Это обычная обязанность StandardAnalyzer.
Пример приложения
Мы будем использовать один из многих архетипов Maven, чтобы создать образец проекта для нашего примера. Чтобы создать проект, выполните следующую команду в каталоге, который вы будете использовать в качестве рабочей области:
mvn архетип: сгенерировать -DgroupId = com.linuxhint.пример -DartifactId = LH-LuceneExample -DarchetypeArtifactId = maven-archetype-quickstart -DinteractiveMode = falseЕсли вы запускаете maven в первый раз, выполнение команды генерации займет несколько секунд, потому что maven необходимо загрузить все необходимые плагины и артефакты, чтобы выполнить задачу генерации. Вот как выглядит результат проекта:
Настройка проекта
После того, как вы создали проект, не стесняйтесь открывать его в своей любимой IDE. Следующим шагом является добавление в проект соответствующих зависимостей Maven. Вот помпон.xml с соответствующими зависимостями:
Наконец, чтобы понять все JAR-файлы, которые добавляются в проект при добавлении этой зависимости, мы можем запустить простую команду Maven, которая позволяет нам увидеть полное дерево зависимостей для проекта, когда мы добавляем к нему некоторые зависимости. Вот команда, которую мы можем использовать:
Зависимость mvn: деревоКогда мы запустим эту команду, она покажет нам следующее дерево зависимостей:
Наконец, мы создаем класс SimpleIndexer, который запускает
импорт Java.io.Файл;
импорт Java.io.FileReader;
импорт Java.io.IOException;
организация импорта.апач.Люцен.анализ.Анализатор;
импортная организация.апач.Люцен.анализ.стандарт.StandardAnalyzer;
импортная организация.апач.Люцен.документ.Документ;
организация импорта.апач.Люцен.документ.StoredField;
импортная организация.апач.Люцен.документ.Текстовое поле;
импортная организация.апач.Люцен.индекс.IndexWriter;
импортная организация.апач.Люцен.индекс.IndexWriterConfig;
организация импорта.апач.Люцен.хранить.FSDirectory;
импортная организация.апач.Люцен.утилита.Версия;
public class SimpleIndexer
приватный статический финал String indexDirectory = "/ Users / shubham / где-нибудь / LH-LuceneExample / Index";
private static final String dirToBeIndexed = "/ Users / shubham / где-то / LH-LuceneExample / src / main / java / com / linuxhint / example";
public static void main (String [] args) выдает исключение
Файл indexDir = новый файл (indexDirectory);
Файл dataDir = новый файл (dirToBeIndexed);
Индексатор SimpleIndexer = новый SimpleIndexer ();
int numIndexed = индексатор.индекс (indexDir, dataDir);
Система.вне.println ("Всего проиндексированных файлов" + numIndexed);
частный индекс int (File indexDir, File dataDir) выдает исключение IOException
Analyzer analyzer = новый StandardAnalyzer (Версия.LUCENE_46);
Конфигурация IndexWriterConfig = новый IndexWriterConfig (Версия.LUCENE_46,
анализатор);
IndexWriter indexWriter = новый IndexWriter (FSDirectory.открыть (indexDir),
config);
Файл [] files = dataDir.listFiles ();
for (Файл f: файлы)
Система.вне.println ("Индексируемый файл" + f.getCanonicalPath ());
Документ doc = новый документ ();
док.добавить (новый TextField ("контент", новый FileReader (f)));
док.add (new StoredField ("имя_файла", f.getCanonicalPath ()));
indexWriter.addDocument (док);
int numIndexed = indexWriter.maxDoc ();
indexWriter.Закрыть();
return numIndexed;
В этом коде мы только что создали экземпляр документа и добавили новое поле, представляющее содержимое файла. Вот результат, который мы получаем, когда запускаем этот файл:
Индексируемый файл / Пользователи / shubham / где-то / LH-LuceneExample / src / main / java / com / linuxhint / example / SimpleIndexer.ЯваВсего проиндексировано файлов 1
Также внутри проекта создается новый каталог со следующим содержимым:
Индексные данные
Мы проанализируем, какие все файлы созданы в этом указателе, в следующих уроках, посвященных Lucene.
Заключение
В этом уроке мы рассмотрели, как работает Apache Lucene, а также создали простой пример приложения, основанного на Maven и java.