Защо е необходим Луцен?
Търсенето е една от най-често срещаните операции, които извършваме няколко пъти на ден. Това търсене може да бъде в множество уеб страници, които съществуват в мрежата или приложение за музика или хранилище на кодове или комбинация от всичко това. Някой може да си помисли, че обикновена релационна база данни също може да поддържа търсене. Това е вярно. Базите данни като MySQL поддържат пълнотекстово търсене. Но какво да кажем за мрежата или приложението за музика, хранилището на кодове или комбинацията от всичко това? Базата данни не може да съхранява тези данни в колоните си. Дори и да го направи, ще отнеме неприемливо време, за да стартирате търсенето толкова голямо.
Пълнотекстовата търсачка може да изпълнява заявка за търсене на милиони файлове наведнъж. Скоростта, с която данните се съхраняват в дадено приложение днес, е огромна. Изпълнението на пълнотекстовото търсене при такъв обем данни е трудна задача. Това е така, защото информацията, от която се нуждаем, може да съществува в един файл от милиарди файлове, съхранявани в мрежата.
Как работи луценът?
Очевидният въпрос, който трябва да ви хрумне, е как е толкова бърз Lucene при изпълнение на заявки за пълнотекстово търсене? Отговорът на това, разбира се, е с помощта на индексите, които създава. Но вместо да създава класически индекс, Lucene използва Инвертирани индекси.
В класически индекс за всеки документ събираме пълния списък с думи или термини, които документът съдържа. В инвертиран индекс за всяка дума във всички документи съхраняваме в кой документ и позиция може да се намери тази дума / термин. Това е високо стандартен алгоритъм, който прави търсенето много лесно. Помислете за следния пример за създаване на класически индекс:
Doc1 -> "This", "is", "simple", "Lucene", "sample", "classic", "inverted", "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 съхранява данни в нормални директории на файловата система или в паметта, ако се нуждаете от повече производителност. Изборът на приложения е изцяло да съхранява данни, където пожелае, база данни, RAM или диск.
- Документи: Данните, които подаваме към Lucene engine, трябва да бъдат преобразувани в обикновен текст. За целта правим обект Document, който представлява източника на данни. По-късно, когато изпълним заявка за търсене, в резултат ще получим списък с обекти на Document, които отговарят на заявката, която сме предали.
- Полета: Документите се попълват с колекция от полета. Полето е просто чифт (име, стойност) елементи. Така че, докато създаваме нов обект на документ, ние трябва да го запълним с този вид сдвоени данни. Когато полето е индексирано обратно, стойността на полето се токенизира и е достъпна за търсене. Сега, докато използваме Fields, не е важно да съхраняваме действителната двойка, а само инвертирания индексиран. По този начин можем да решим кои данни са само за търсене и не са важни за запазване. Нека разгледаме пример тук:
Индексиране на полета
В горната таблица решихме да съхраним някои полета, а други не се съхраняват. Полето на тялото не се съхранява, а индексира. Това означава, че имейлът ще бъде върнат в резултат, когато се изпълни заявката за едно от Условията за основното съдържание.
- Условия: Термините представляват дума от текста. По този начин термините се извличат от анализа и токенизирането на стойностите на полетата Терминът е най-малката единица, по която се извършва търсенето.
- Анализатори: Анализаторът е най-важната част от процеса на индексиране и търсене. Анализаторът е този, който свързва обикновения текст в токени и условия, за да могат да бъдат търсени. Е, това не е единствената отговорност на анализатора. Анализаторът използва токенизатор, за да прави токени. Анализаторът изпълнява и следните задачи:
- Stemming: Анализатор преобразува думата в Stem. Това означава, че „цветя“ се превръща в основната дума „цвете“. Така че, когато се изпълни търсене на „цвете“, документът ще бъде върнат.
- Филтриране: Анализаторът филтрира и думите за спиране като „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;
внос орг.апаш.луцен.util.Версия;
публичен клас SimpleIndexer
private static final String indexDirectory = "/ Потребители / shubham / някъде / LH-LuceneExample / Index";
частен статичен финален низ dirToBeIndexed = "/ Users / shubham / някъде / LH-LuceneExample / src / main / java / com / linuxhint / example";
public static void main (String [] args) хвърля изключение
File indexDir = нов файл (indexDirectory);
File dataDir = нов файл (dirToBeIndexed);
Индексатор на SimpleIndexer = нов SimpleIndexer ();
int numIndexed = индексатор.индекс (indexDir, dataDir);
Система.навън.println ("Общо индексирани файлове" + numIndexed);
private int index (File indexDir, File dataDir) хвърля IOException
Анализатор анализатор = нов StandardAnalyzer (Версия.LUCENE_46);
IndexWriterConfig config = нов IndexWriterConfig (Версия.LUCENE_46,
анализатор);
IndexWriter indexWriter = нов IndexWriter (FSDirectory.отворен (indexDir),
конфиг);
Файл [] файлове = dataDir.listFiles ();
за (Файл f: файлове)
Система.навън.println ("Файл за индексиране" + f.getCanonicalPath ());
Документ на документ = нов документ ();
док.добави (нов TextField ("съдържание", нов FileReader (f)));
док.add (new StoredField ("fileName", f.getCanonicalPath ()));
indexWriter.addDocument (doc);
int numIndexed = indexWriter.maxDoc ();
indexWriter.близо();
връщане numIndexed;
В този код току-що направихме екземпляр на Document и добавихме ново поле, което представлява съдържанието на файла. Ето изхода, който получаваме, когато стартираме този файл:
Индексиране на файл / Потребители / shubham / някъде / LH-LuceneExample / src / main / java / com / linuxhint / example / SimpleIndexer.javaОбщо индексирани файлове 1
Също така, в проекта се създава нова директория със следното съдържание:
Данни за индекса
Ще анализираме какви файлове са създадени в този индекс в още уроци за Lucene.
Заключение
В този урок разгледахме как работи Apache Lucene и също така направихме прост пример за приложение, базирано на Maven и Java.