19 сентября 2019

Полнотекстовый поиск по содержимому файлов

    Многие программисты сталкиваются с тем, что их информационная система должна иметь полнотекстовый поиск. На помощь им приходят разработчики СУБД, которые предлагают свои решения. Встроенный механизм полнотекстового поиска есть у всех ведущих СУБД: Oracle, SQL Server, MySQL, PostgreSQL... Но не все они, как Oracle Text, умеют индексировать содержимое документов в форматах MS Office, PDF, XML, HTML... плюс к этому у многих есть проблемы с морфологией русского языка и производительностью.
    Единственным выходом является использование специальных поисковых систем. Наиболее распространенными являются системы построенные на базе библиотеки Lucene: Elasticsearch, Solr и Sphinx. Мой выбор пал на Elasticsearch.
    Для поиска по содержимому файлов у Elasticsearch есть плагин Ingest Attachment Processor. Работа этого плагина основана на библиотеке Apache Tika, которая может извлекать метаданные и текст из более чем тысячи различных типов файлов. Рассмотрим на примерах работу с плагином Ingest Attachment Processor.

1. Установка плагина Ingest Attachment Processor

Допустим, что Elasticsearch и Kibana у нас уже установлены, поэтому сразу перейдем к установке плагина. Перед ней желательно JVM дать побольше прав. Для этого в файл "jdk\lib\security\default.policy" добавляем блок:
grant {
  permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
  permission java.lang.RuntimePermission "accessClassInPackage.sun.*";
  permission java.lang.RuntimePermission "accessDeclaredMembers";
  permission java.lang.RuntimePermission "getClassLoader";
  permission java.security.SecurityPermission "createAccessControlContext";
  permission java.security.SecurityPermission "insertProvider";
  permission java.security.SecurityPermission "putProviderProperty.BC";
};
Плагин может быть установлен с помощью менеджера плагинов:
bin\elasticsearch-plugin install ingest-attachment
или из предварительно скачанного файла:
bin\elasticsearch-plugin install file:///d:\es\ingest-attachment-7.3.0.zip
После установки плагина необходимо перезапустить Elasticsearch. Посмотреть список установленных плагинов можно командой:
bin\elasticsearch-plugin list
2. Подготовка Elasticsearch к индексированию файлов

Все общение с Elasticsearch можно вести с помощью REST запросов. Например, получим информацию о локальном сервере Elasticsearch:
GET http://localhost:9200
где "localhost:9200" - адрес и порт узла кластера серверов Elasticsearch


2.1 Для начала в узле ingest, нужно создать "конвейер" (pipeline) и добавить в него "процессоры" (processors), которые работают с полями документа:
PUT http://localhost:9200/_ingest/pipeline/attachment
{
  "description" : "Files information",
  "processors" : [
    {
      "attachment" : {"field" : "data"}
    }
  ]
}
Если плагин ingest-attachment был установлен правильно, то Elasticsearch вернет JSON-ответ {"acknowledged": true}


2.2. Теперь создадим "индекс" (аналог таблицы в реляционной базе данных) для хранения нашей информации:

PUT http://localhost:9200/fs_index


В Kibana мы видим, у нас теперь есть индекс "fs_index":
Маппинг полей можно не производить, т.к. плагин сделает его сам.

3. Загрузка и индексирование файлов в Elasticsearch

Загрузка файла в Elasticsearch производится с помощью REST запроса
PUT http://localhost:9200/индекс/_doc/IDдокумента?pipeline=attachment
При этом содержимое файла нужно отправить в Base64. Загрузим несколько файлов для тестирования.

Первый файл "test.txt" содержит текст:
test
тест
Загружаем:
PUT http://localhost:9200/fs_index/_doc/1?pipeline=attachment
{"filename": "test.txt", "data": "dGVzdArRgtC10YHRgg=="}

В Kibana мы видим, у нашего индекса "fs_index" появился первый документ:

Просмотреть содержимое файла и информацио о нем можно с помощью запроса:
GET http://localhost:9200/fs_index/_doc/IDдокумента

Загружаем остальные файлы:

Второй файл "2.txt"
not a test
Загружаем:
PUT http://localhost:9200/fs_index/_doc/2?pipeline=attachment
{"filename": "2.txt", "data": "bm90IGEgdGVzdA=="}
Третий файл "3.txt"
third file
Загружаем:
PUT http://localhost:9200/fs_index/_doc/3?pipeline=attachment
{"filename": "3.txt", "data": "dGhpcmQgZmlsZQ=="}
Четвертый файл "word.docx" (формат MS Word)
Test
files
Загружаем:
PUT http://localhost:9200/fs_index/_doc/4?pipeline=attachment
{"filename": "word.docx", "data": "UEsDBB ... вырезала цензура... AAA="}

4. Поиск по содержимому файлов в Elasticsearch

Для поиска по содержимому файлов выполним REST запрос
POST http://localhost:9200/fs_index/_doc/_search
{"query": {"match": {"attachment.content": "test"}}}

Слово "test" встречается в 3-х загруженных файлах: "test.txt", "2.txt" и "word.docx"


Что бы не таскать каждый раз содержимое файла немного изменим запрос, что бы он возвращал только имя файла:

POST http://localhost:9200/fs_index/_doc/_search
{
"query": {"match": {"attachment.content": "test"}},
"_source": ["filename"]
}

Теперь попробуем нечеткий поиск:
POST http://localhost:9200/fs_index/_doc/_search
{
"query": {"fuzzy": {"attachment.content": "file"}},
 "_source": ["filename"]
}
Слово "file" встречается в 2-х загруженных файлах: "3.txt" (в нем есть слово "file") и "word.docx" (в нем есть слово "files"):


Elasticsearch имеет очень мощный API для поиска информации, по которому можно написать много статей.

5. Изменение файлов в Elasticsearch

5.1. Если содержимое файла изменилось то, просто загрузим его в Elasticsearch с тем же самым ID:
PUT http://localhost:9200/fs_index/_doc/1?pipeline=attachment
{"filename": "test.txt", "data": "dGVzdA2rC10YHRgg=="}

5.2. Удаление файла
DELETE http://localhost:9200/fs_index/_doc/2

Документация:
Download Elasticsearch
Elasticsearch Reference
Installing Elasticsearch

4 комментария:

  1. Все очень интересно, но не хватает основ, как развернуть, что может понадобится, обновление индексов и прочие вещи.

    ОтветитьУдалить
  2. Спасибо! Там основы элементарные. Для ознакомления Elasticsearch ставится с базовыми настройками с полпинка, что Windows, что под Ubuntu. Цель заметки была показать простоту, с которой можно организовать полноценный поиск по содержимому файлов. А дальше очень широкий простор для настроек под свои задачи, как Elasticsearch, так и самого Ingest Attachment Processor. А возможностей там море :)

    ОтветитьУдалить
  3. Комментарий не по теме. Но уж не знаю куда писать. Ваши посты идут в рассылку на делфифидс2.0. Но там из всех рассылок только ваши не работают, нет перехода на основной пост. Поэтому предполагаю что проблема у вас? Может посмотрите?
    З.Ы. Что тут в блоге, что на делфифидс2.0 нет контактов для связи, вообще непонятно куда и кому писать о багах

    ОтветитьУдалить
  4. Я уже писал Александру - это баг его парсера. На делфифидс 1.0 такой проблемы не было.

    ОтветитьУдалить