Статьи

Поиск стал проще с Apache Lucene 4.3

Lucene — это механизм полнотекстового поиска, написанный на Java, который может предоставить мощные возможности поиска любому приложению. В основе Lucene лежит файл на основе полнотекстового индекса. Lucene предоставляет API для создания этого индекса, а затем добавляет и удаляет содержимое этого индекса. Далее это позволяет искать и извлекать информацию из этого индекса, используя мощные алгоритмы поиска. Сохраненные данные могут быть получены из разнородных источников, таких как база данных, файловая система и веб-сайты. Прежде чем начать, давайте задуматься о нескольких условиях.

Перевернутый индекс

Инвертированный индекс — это структура данных, в которой хранится сопоставление контента и местоположение объекта, в котором находится этот контент. Чтобы было понятнее, вот несколько примеров

  1. Книжный указатель — Указатель книги содержит важные слова и страницы, которые содержат эти слова. Таким образом, книжный указатель помогает нам перемещаться по страницам, которые содержат определенное слово.
  2. Перечень вин с использованием ценовых диапазонов — ценовой диапазон является содержимым, а winename является объектом, который имеет этот ценовой диапазон
  3. Веб-индекс — список адресов веб-сайтов по ключевым словам. Например, список всех веб-страниц, содержащих ключевые слова «Apache Lucene»
  4. Корзина — Список товаров в корзине по категориям.  

Фасетный поиск

Любой объект может иметь несколько свойств, каждое из которых является фасетом этого объекта. Фасетный поиск позволяет нам искать коллекцию объектов на основе нескольких граней. Фасетный поиск также известен как фасетная навигация или граненый просмотр, и он позволяет нам искать информацию, которая организована в соответствии с граненой организационной структурой.

Рассмотрим пример товара в корзине. Элемент может иметь несколько аспектов, таких как категория, название, цена, цвет, вес и т. Д. Теперь поиск по фасету позволит нам искать все элементы, которые относятся к категории сада, имеют красный цвет и находятся в диапазоне цен от 30 рупий до рупий. +0,40.

Lucene предоставляет нам API

  1. Создать инвертированный индекс.
  2. Хранить информацию в соответствии с граненой классификацией.
  3. Получить информацию с помощью фасетного поиска.

Все это делает Lucene суперскоростной поисковой системой, которая возвращает супер релевантные результаты поиска.

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

  1. Поиск по релевантности
  2. Фраза, близость, поиск по шаблону.
  3. Штекерный анализатор.
  4. Граненый Поиск.
  5. Полевая сортировка
  6. Диапазон запросов
  7. Поиск индекса Mutliple.
  8. Быстрая индексация 150 ГБ / час.
  9. Простое резервное копирование и восстановление.
  10. Небольшое требование к оперативной памяти.
  11. Добавочное добавление и быстрый поиск.

Для полного списка посетите здесь: http://lucene.apache.org/core/features.html

Lucene Концепции и терминология

  1. Индексирование. Индексирование включает добавление документа в индекс Lucene с помощью класса « IndexWriter ».
  2. Поиск — Поиск включает извлечение документа из индекса Lucene с помощью класса « IndexSearcher ».
  3. Документдокумент Lucene — это единица поиска и индексации. Например, товар в корзине. Индекс Lucene может содержать миллионы документов.
  4. Поля — Поля являются свойствами любого документа. Другими словами, поля — это фасеты документа, который является объектом. Например, категория товара в корзине. Каждый документ может иметь несколько полей.
  5. Запросы — Lucene имеет свой собственный язык запросов. Это позволяет нам искать документ на основе нескольких полей. Мы можем присвоить вес полю, а также использовать логические выражения, такие как и или или для запроса. Например — Вернуть все товары в корзине, которые принадлежат к категории сад или дом, имеют красный цвет и цену ниже 1000 рупий.
  6. Анализаторы — когда текст поля должен быть проиндексирован, его необходимо преобразовать в его самую основную форму. Сначала они токенизируются, а затем преобразуются в строчные, сигуляризованные, лишены меток. Эти задачи выполняются анализаторами. Анализаторы сложны, и мы нуждаемся в глубоком изучении того, как их использовать. Чаще всего встроенные анализаторы не подходят для наших требований, в этом случае мы можем создать новый. Для этого урока мы будем использовать StandardAnalyzer, так как они содержат большинство основных функций, которые нам необходимы.

Цель учебника

  1. Попробуйте создать индекс Lucene.
  2. Вставьте книжные записи в этом.
  3. Выполнение различных видов поиска по этому индексу.

Элемент книги будет иметь следующие аспекты

  1. Название книги (Строка
  2. Автор книги (Строка)
  3. Книга Catgory (Строка)
  4. #Pages (целое)
  5. Цена (с плавающей точкой)

Код для этого урока был передан SVN. Его можно проверить по адресу : https://www.assembla.com/code/weblog4j/subversion/nodes/24/SpringDemos/trunk

Это расширенный проект с большим количеством учебников. Классы lucene находятся в пакете com.aranin.spring.lucene

  1. LuceneUtil — этот класс содержит метод utitlity для создания индекса, создания IndexWriter и IndexSearcher.
  2. MySearcherManager — этот класс использует LuceneUtil и выполняет поиск по индексу.
  3. MyWriterManager — этот класс использует LuceneUtil и выполняет записи в индекс.

Пошаговое прохождение

1. Зависимости — зависимости могут быть добавлены через Maven

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<dependency>
        <artifactId>lucene-core</artifactId>
        <groupId>org.apache.lucene</groupId>
        <type>jar</type>
        <version>${lucene-version}</version>
      </dependency>
 
      <dependency>
        <artifactId>lucene-queries</artifactId>
        <groupId>org.apache.lucene</groupId>
        <type>jar</type>
        <version>${lucene-version}</version>
      </dependency>
 
      <dependency>
        <artifactId>lucene-queryparser</artifactId>
        <groupId>org.apache.lucene</groupId>
        <type>jar</type>
        <version>${lucene-version}</version>
      </dependency>
 
      <dependency>
        <artifactId>lucene-analyzers-common</artifactId>
        <groupId>org.apache.lucene</groupId>
        <type>jar</type>
        <version>${lucene-version}</version>
      </dependency>
 
      <dependency>
        <artifactId>lucene-facet</artifactId>
        <groupId>org.apache.lucene</groupId>
        <type>jar</type>
        <version>${lucene-version}</version>
      </dependency>

2. Создание индекса . Индекс можно создать, создав IndexWriter в режиме создания.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
public void createIndex() throws Exception {
 
    boolean create = true;
    File indexDirFile = new File(this.indexDir);
    if (indexDirFile.exists() && indexDirFile.isDirectory()) {
       create = false;
    }
 
    Directory dir = FSDirectory.open(indexDirFile);
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43);
    IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_43, analyzer);
 
    if (create) {
       // Create a new index in the directory, removing any
       // previously indexed documents:
       iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
    }
 
    IndexWriter writer = new IndexWriter(dir, iwc);
    writer.commit();
    writer.close(true);
 }
  • indexDir — это каталог, в котором вы хотите создать свой индекс.
  • Каталог — это плоский список файлов, используемых для хранения индекса. Это может быть RAMDirectory, FSDirectory или каталог на основе БД.
  • FSDirectory реализует каталог и сохраняет индексы в файлах в файловой системе.
  • IndexWriterConfig. Режим Open создает писателя в режиме create или create_append или в режиме appned. Режим создания создает новый индекс, если он не существует, или перезаписывает существующий. В целях создания мы создаем существующий.
  • Вызов метода выше создает пустой индекс.

3. Запись в указатель. После создания указателя мы можем записать в него документы. Это можно сделать с помощью следующего.

01
02
03
04
05
06
07
08
09
10
11
12
public void createIndexWriter() throws Exception {
 
     boolean create = true;
     File indexDirFile = new File(this.indexDir);
 
     Directory dir = FSDirectory.open(indexDirFile);
     Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43);
<span style="color: #222222; font-family: 'Courier 10 Pitch', Courier, monospace; line-height: 21px;">IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_43, analyzer);</span>
     iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
     this.writer = new IndexWriter(dir, iwc);
 
    }

Выше метод создает писатель в режиме create_append. В этом режиме, если индекс создан, он не будет перезаписан. Вы можете заметить, что этот метод не закрывает писателя. Он просто создает и возвращает его. Создание IndexWriter является дорогостоящей операцией. Таким образом, мы не должны создавать писателя каждый раз, когда нам нужно записать документ в индекс. Вместо этого мы должны создать пул IndexWriter и использовать систему потоков, чтобы получить средство записи из пула для записи в индекс и затем вернуть средство записи в пул.

01
02
03
04
05
06
07
08
09
10
11
public void addBookToIndex(BookVO bookVO) throws Exception {
     Document document = new Document();
     document.add(new StringField("title", bookVO.getBook_name(), Field.Store.YES));
     document.add(new StringField("author", bookVO.getBook_author(), Field.Store.YES));
     document.add(new StringField("category", bookVO.getCategory(), Field.Store.YES));
     document.add(new IntField("numpage", bookVO.getNumpages(), Field.Store.YES));
     document.add(new FloatField("price", bookVO.getPrice(), Field.Store.YES));
     IndexWriter writer =  this.luceneUtil.getIndexWriter();
     writer.addDocument(document);
     writer.commit();
 }

Мы не создаем писателя в коде при вставке. Вместо этого мы использовали предварительно созданный модуль записи, который хранился как переменная экземпляра.

4. Поиск в индексе. Это снова выполняется в два этапа. 1. Создание IndexSearcher 2. Создание запроса и выполнение поиска.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
public void createIndexSearcher(){
    IndexReader indexReader = null;
    IndexSearcher indexSearcher = null;
    try{
         File indexDirFile = new File(this.indexDir);
         Directory dir = FSDirectory.open(indexDirFile);
         indexReader  = DirectoryReader.open(dir);
         indexSearcher = new IndexSearcher(indexReader);
    }catch(IOException ioe){
        ioe.printStackTrace();
    }
 
    this.indexSearcher = indexSearcher;
 }

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public List<BookVO> getBooksByField(String value, String field, IndexSearcher indexSearcher){
     List<BookVO> bookList = new ArrayList<BookVO>();
     Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43);
     QueryParser parser = new QueryParser(Version.LUCENE_43, field, analyzer);
 
     try {
         BooleanQuery query = new BooleanQuery();
         query.add(new TermQuery(new Term(field, value)), BooleanClause.Occur.MUST);
 
        //Query query = parser.Query(value);
        int numResults = 100;
        ScoreDoc[] hits =   indexSearcher.search(query,numResults).scoreDocs;
        for (int i = 0; i < hits.length; i++) {
             Document doc = indexSearcher.doc(hits[i].doc);
             bookList.add(getBookVO(doc));
        }
 
     } catch (IOException e) {
         e.printStackTrace();
     }
 
     return bookList;
}

IndexSearcher был предварительно создан и передан методу. Основная часть поиска — формирование запросов. Lucene поддерживает множество разных типов запросов.

  1. TermQuery
  2. BooleanQuery
  3. WildcardQuery
  4. PhraseQuery
  5. PrefixQuery
  6. MultiPhraseQuery
  7. FuzzyQuery
  8. RegexpQuery
  9. TermRangeQuery
  10. NumericRangeQuery
  11. ConstantScoreQuery
  12. DisjunctionMaxQuery
  13. MatchAllDocsQuery

Вы можете выбрать соответствующие запросы для ваших поисков. Синтаксис языка запросов можно узнать здесь: http://lucene.apache.org/core/old_versioned_docs/versions/2_9_1/queryparsersyntax.pdf

Ресурсы

  1. http://lucene.apache.org/core/old_versioned_docs/versions/2_9_1/queryparsersyntax.pdf
  2. http://lucene.apache.org/core/old_versioned_docs/versions/3_1_0/api/all/org/apache/lucene/index/IndexWriterConfig.OpenMode.html
  3. http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/api/all/org/apache/lucene/store/FSDirectory.html
  4. https://today.java.net/pub/a/today/2003/07/30/LuceneIntro.html
  5. http://www.lucenetutorial.com/lucene-query-syntax.html
  6. http://lucene.apache.org/core/4_3_0/core/org/apache/lucene/search/Query.html

Резюме

Поиск остается основой любого контент-ориентированного приложения. Традиционный поиск по БД не очень силен и оставляет желать лучшего. Таким образом, существует потребность в быстром, точном и мощном поисковом решении, которое можно легко включить в код приложения. Lucene прекрасно восполняет этот пробел, делает поиск быстрым и поддерживается мощным набором алгоритмов поиска, таких как ранжирование по релевантности, фраза, подстановочный знак, близость и ранжированный поиск. Это также экономит место и память. Неудивительно, что так много приложений было построено поверх Lucene. В этой статье рассказывается о том, как дать дорогим читателям инструменты для начала работы с Lucene. Есть еще много чего сказать, но разве вы не хотите исследовать некоторые самостоятельно?

Справка: поиск стал проще с Apache Lucene 4.3 от нашего партнера по JCG Нираджа Сингха в блоге Weblog4j .