https://en.wikipedia.org/wiki/Inverted_index
Для быстрого и гибкого поиска по словам или фразам среди множества документов подготавливают структуру данных, которая представляет собой упорядоченный список всех слов, встречающихся во множестве документов, каждому слову сопоставляется список идентификаторов документов и позиций встречания этого слова в каждом документе.
На похожем принципе основаны глоссарии в книгах.
Предполагается, что операций поиска будет существенно больше, нежели операций изменения множества документов.
Набор текстовых файлов в кодировке UTF-8. Каждый файл - документ. Словом считается последовательность символов, ограниченная пробельными символами с обеих сторон. Символы, отличные от букв, цифр и пробельных символов, расположенные по краям слова, должны удаляться. Слова в файле нумеруются с нуля и позиция слова - это его номер. Если слово встречается в файле несколько раз, то у него будет несколько позиций в этом файле (нумерация слов не учитывает повторения, т.е. каждое повторное вхождение какого-либо слова нумеруется, как новое слово).
Для упрощения будем считать, что в файлах встречается лишь подмножество UTF-8, совпадающее с 7-битной кодировкой ASCII. Таким образом, для классификации
символов можно использовать функции стандартной библиотеки std::isspace
, std::ispunct
и т.п.
Пример: "A goal of a search engine implementation is to optimize the speed of the query."
A | goal | of | a | search | engine | implementation | is | to | optimize | the | speed | of | the | query |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
"EST assembly was an early strategy, dating from the mid-1990s to the mid-2000s,"
EST | assembly | was | an | early | strategy | dating | from | the | mid-1990s | to | the | mid-2000s |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
Одно или более слов составляет поисковый запрос. Требуется найти все документы, каждый из которых включает в себя все слова запроса.
Если фрагмент поискового запроса или весь запрос заключён в кавычки, то слова в кавычках должны искаться как точная фраза, т.е. встречаться в документе именно в таком порядке, друг за другом и полностью (т.е. фраза в кавычках должна полностью присутствовать в документе).
В запросе символы интерпретируются так же, как и в документе, за исключением прямых кавычек "
, которые служат для обозначения "фраз".
Фраза задаёт лишь последовательность слов в представлении документа, как цепочки слов - например, символы пунктуации внутри фразы обрабатываются так же, как и в других случаях.
Пример: Поиск фразы '"early strategy dating"' в документах из предыдущего примера будет давать второй документ.
Для простоты будем работать с индексом в памяти, без сохранения на диск.
Вам предлагается реализовать такой интерфейс:
class Searcher
{
public:
using Filename = std::string; // or std::filesystem::path
// index modification
void add_document(const Filename & filename);
void remove_document(const Filename & filename);
// queries
class DocIterator
{
public:
using value_type = const Filename;
...
};
class BadQuery : public std::exception
{
...
};
std::pair<DocIterator, DocIterator> search(const std::string & query);
};
- Допускается для имён файлов вместо
std::string
использоватьstd::filesystem::path
.
Возможны две операции, меняющие индекс:
- Добавление документа - входными данными являются имя файла и поток ввода, из которого требуется прочитать содержимое файла. Результатом должно стать обновление индекса всеми словами из этого документа. Обратите внимание, что это может быть также обновление уже проиндексированного документа - тогда требуется обновить индекс таким образом, чтобы он отражал новое содержимое документа.
- Удаление документа - входными данными является имя файла. Результатов должно стать удаление информации, связанной с этим документом, из индекса.
Searcher::search
принимает строку поискового запроса, а возвращает пару итераторов, задающих диапазон найденных документов (по их именам). Метод вернёт значение, если запрос был корректен.- Поисковый запрос должен разбиваться на слова по тем же правилам, что и файл с текстом документа, за исключением обработки кавычек - символ
"
должен обрабатываться и интерпретироваться, как открывающая или закрывающая кавычка. - В запросе могут быть ошибки - например, отсутствие слов или непарные кавычки, в этом случае результатом поиска будет выброс исключения
BadQuery
с сообщением об ошибке, начинающееся с "Search query syntax error:".