3. Индексатор
Цель
Реализовать построитель прямого и обратного индекса. Покрыть тестами.
Основные понятия
Терм — это нормализованное слово, помещаемое в словарь поисковой системы. В нашем случае термами мы будем считать n-граммы, полученные от парсера.
В основе любой поисковой системы лежит обратный индекс. Это ассоциативная структура данных, ключами в которой являются термы, а значениями — список идентификаторов документов и позиций термов в этих документах.
На входе у индексатора документы, содержащие слова. Индексатор «разворачивает»
связь Документ -> [слова] и строит структуру терм -> [документы].
Прямой индекс — ассоциативная структура данных, в которой ключ — идентификатор документа, значение — сам документ.
Пример
Пусть на входе у индексатора следующие документы:
id text
199903 The Matrix
200305 The Matrix Reloaded
200311 The Matrix Revolutions
От парсера индексатор получает следующие термы и их позиции:
id text
199903 mat:0 matr:0 matri:0 matrix:0
200305 mat:0 matr:0 matri:0 matrix:0 rel:1 relo:1 reloa:1 reload:1
200311 mat:0 matr:0 matri:0 matrix:0 rev:1 revo:1 revol:1 revolu:1
Тогда обратный индекс можно схематично изобразить так:
term entries
mat: {199903: [0], 200305: [0], 200311: [0]}
matr: {199903: [0], 200305: [0], 200311: [0]}
matri: {199903: [0], 200305: [0], 200311: [0]}
matrix: {199903: [0], 200305: [0], 200311: [0]}
rel: {200305: [1]}
relo: {200305: [1]}
reloa: {200305: [1]}
reload: {200305: [1]}
rev: {200311: [1]}
revo: {200311: [1]}
revol: {200311: [1]}
revolu: {200311: [1]}
Декомпозиция
Один из возможных вариантов декомпозиции:
Здесь:
IndexBuilder— stateful-класс, накапливающий данные для индекса по мере добавления документов.Index::docs— прямой индекс.Index::entries— обратный индекс.Сериализация индекса вынесена в отдельный класс
TextIndexWriterдля упрощения тестирования.
Формат индекса
Ниже приведен рекомендуемый формат индекса. Вы можете спроектировать свой.
index
|-- docs
| |-- 101
| |-- 102
| `-- 103
`-- entries
|-- 3adb7b
|-- 9ea46a
`-- c9a868
index/docs— прямой индекс.index/docs/<document_id>— проиндексированный документindex/entries— обратный индекс. Имена вложенных файлов — первые три байта хеша терма. В качестве хеша можно использовать md5 или sha256 (https://github.com/okdshin/PicoSHA2).
Формат файлов обратного индекса index/entries/<term-hash>:
<term> <doc_count> [<doc_id> <pos_count> [<pos> …] …]
...
Здесь:
term— текст терма.doc_count— количество документов, в которые входит терм. За ним следуют списки позиций для каждого документа.doc_id— идентификатор документа.pos_count— количество вхождений термаtermв документdoc_idpos— номер токена, в который входит терм.
Для примера выше вхождение терма matrix будет выглядеть так:
matrix 3 199903 1 0 200305 1 0 200311 1 0