Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <iostream>
- #include <set>
- #include <string>
- #include <utility>
- #include <vector>
- using namespace std;
- const int MAX_RESULT_DOCUMENT_COUNT = 5;
- string ReadLine()
- {
- string s;
- getline(cin, s);
- return s;
- }
- int ReadLineWithNumber()
- {
- int result = 0;
- cin >> result;
- ReadLine();
- return result;
- }
- // (6) разбивает входящую строку на отдельные слова, возвращает вектор слов входящей строки
- vector<string> SplitIntoWords(const string &text)
- {
- vector<string> words;
- string word;
- for (const char c : text)
- {
- if (c == ' ')
- {
- if (!word.empty())
- {
- words.push_back(word);
- word.clear();
- }
- }
- else
- {
- word += c;
- }
- }
- if (!word.empty())
- {
- words.push_back(word);
- }
- return words;
- }
- struct Document
- {
- int id;
- int relevance;
- };
- bool HasDocumentGreaterRelevance(const Document &lhs, const Document &rhs)
- {
- return lhs.relevance > rhs.relevance;
- }
- class SearchServer
- {
- public:
- /* (7)
- это второй используемый метод-процедура в программе. его задача получить порядковый номер
- документа int document_id, например, 1, и сам документ, например "это очередной документ",
- и наполняет поле-переменную класса vector<DocumentContent> documents_; сам DocumetContent
- так определен (это самописный тип, о нем уже было), что первое его поле id, второе words,
- а сам вектор документов будет заполнен например так:
- DocumentContent documents_ = {
- {1, {"это", "очередной", "документ"}},
- {1, {"это", "тоже", "документ"}}
- }
- */
- void AddDocument(int document_id, const string &document)
- {
- const vector<string> words = SplitIntoWordsNoStop(document, stop_words_);
- documents_.push_back({document_id, words});
- }
- /* (5)
- это первый вызываемый метод, в него попадает строка стоп слов по типу: "это стоп слово",
- а выходит ничего, потому что тип возвращаемого значения void, кажется, в старые времена
- это называлось процедурой (функция что-то делает и возвращает, процедура просто что-то делает);
- эта процедура-метод наполняет поле-переменную класса set<string> stop_words_;
- */
- void SetStopWords(const string &text)
- {
- for (const string &word : SplitIntoWords(text))
- {
- stop_words_.insert(word);
- }
- }
- /* (11)
- метод FindTopDocuments вызывается для выдачи максимум 5 документов, соответствующих исходному
- поисковому запросу; он принимает запрос в виде "это запрос на поиск" -- "сырой" запрос, не разбитый на
- отдельные слова, дальше он их разбивает при помощи функции ParseQuery, объявленной в приватной области
- (в приватной, т.к. она необходима для обслущивания работы методов внутри класса, а не для вызова из функции main);
- далее вызывается также приватная функция FindAllDocuments, которая принимает уже разбитый на слова поисковый запрос
- в виде множества слов, входящих в запрос set<string> по типу {"это", "поисковый", "запрос"}; ответ от функции
- FindAllDocuments будет отсортирован с применением компаратора HasDocumentGreaterRelevance и выдан для печати в
- функцию main, откуда и вызывался метод FindTopDocuments
- */
- vector<Document> FindTopDocuments(const string &raw_query)
- {
- const set<string> query_words = ParseQuery(raw_query);
- auto matched_documents = FindAllDocuments(query_words);
- sort(matched_documents.begin(), matched_documents.end(), HasDocumentGreaterRelevance);
- if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT)
- {
- matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
- }
- return matched_documents;
- }
- private:
- struct DocumentContent
- {
- int id = 0;
- vector<string> words;
- };
- // (12) разбивает поданную строку на слова, возвращает множество слов, в которое не входят стоп-слова, содержащиеся в строке
- set<string> ParseQuery(const string &query_text)
- {
- set<string> query_words;
- for (const string &word : SplitIntoWordsNoStop(query_text, stop_words_))
- {
- query_words.insert(word);
- }
- return query_words;
- }
- // (8) разбивает поданную строку на слова известной функцией, возвращает вектор строк, в котором нет стоп-слов
- vector<string> SplitIntoWordsNoStop(const string &text, const set<string> &stop_words)
- {
- vector<string> words;
- for (const string &word : SplitIntoWords(text))
- {
- if (stop_words.count(word) == 0)
- {
- words.push_back(word);
- }
- }
- return words;
- }
- /* (13)
- ну и последний штрих -- также приватная функция MatchDocument, которая занимается матчингом конкретного документа
- и поискового запроса; принимает сам документ в виде вестора строк, например vector<string> doc = {"сам", "документ"}
- и поисковый запрос в виде множества слов в виде set<string> query = {"слово", "и", "еще", "слово"}, перебирая слова
- в документе, в итоге вернет число -- сколько слов из поискового запроса попадаются в документе
- */
- static int MatchDocument(const vector<string> document, const set<string> &query_words)
- {
- if (query_words.empty())
- {
- return 0;
- }
- set<string> matched_words;
- for (const string &word : document)
- {
- if (matched_words.count(word) != 0)
- {
- continue;
- }
- if (query_words.count(word) != 0)
- {
- matched_words.insert(word);
- }
- }
- return static_cast<int>(matched_words.size());
- }
- /* (12)
- функция FindAllDocuments приватная, она необходима для работы методов класса, поэтому скрывается от внешнего
- пользователя; она примет распарсенный на слова поисковый запрос в виде множества слов, будет брать из поля
- documents_ документы и матчить их при помощи приватной функции MatchDocument; показатель мэтча это пересечение
- множества слов запроса и документа, иначе говоря -- искомая релевантность
- */
- vector<Document> FindAllDocuments(const set<string> &query_words)
- {
- vector<Document> matched_documents;
- for (const auto &document : documents_)
- {
- const int relevance = MatchDocument(document.words, query_words);
- if (relevance > 0)
- {
- matched_documents.push_back({document.id, relevance});
- }
- }
- return matched_documents;
- }
- vector<DocumentContent> documents_;
- set<string> stop_words_;
- };
- SearchServer CreateSearchServer()
- {
- /* (2)
- при конструировании черного-ящика-поискового-сервера, который будет на ввод пользователя выводить
- документы согласно их релевантности запросу, считывается строка стоп-слов
- */
- string stop_words = ReadLine();
- /* (3)
- затем создается поисковый сервер -- переменная server типа SearchServer.
- SearchServer это "класс" -- объект с данными и методами доступа к данным, разработан выше
- */
- SearchServer server;
- /* (4)
- здесь сервер через метод заполнит одно из двух своих полей -- поле стоп-слов, это вектор строк,
- который имеет вид set<string> stop_words_;
- */
- server.SetStopWords(stop_words);
- /*
- здесь считается число документов, и в цикле через метод заполнится второе поле -- поле документов,
- которое имеет вид vector<DocumentContent> documents_;
- коротко это вектор документов. DocumentContent это так называемая структура, это по сути
- самописный тип данных в котором можно к полям обращаться через точку по имени. поля это
- переменные, хранящие что-то (данные);
- в данном случае случае структура DocumentContent имеет вид:
- struct DocumentContent
- {
- int id = 0;
- vector<string> words;
- };
- первое переданное значение будет ожидаться как целое число, к нему можно обратиться по имени id, а
- означает оно номер документа;
- второе переданное значение будет ожидаться как вектор строк, к нему можно будет обратиться
- по имени words, а означать оно будет слова, на которые по пробелам побит документ из базы данных,
- по которй ведется поиск релевантных документов
- эта структура определяется в приватной области класса, она просто делает код более читаемым.
- например, определив
- DocumentContent my_document = {1, {"abacaba", "abcbdbba", "ababababa"}};
- я теперь могу написать
- cout << "первое слово документа " << my_document.id << " -- " << my_document.words[0] << endl;
- и выведется: первое слово документа 1 -- abacaba
- */
- int count_docs = ReadLineWithNumber();
- for (int doc_id = 0; doc_id < count_docs; ++doc_id)
- {
- string document = ReadLine();
- server.AddDocument(doc_id, document);
- }
- return server;
- }
- int main()
- {
- /* (1)
- делаю поисковый сервер. SearchServer это как тип int, vector<string> и тд. только
- называется от классом и является черным ящиком, в котором хранится инфа в виде "полей" класса,
- и интерфейсы взаимодействия с классом, которые называются методы. методы это по сути функции, но
- специализирующиеся в работе только над полями класса; поля класса это переменные какого-то типа,
- например set<string>, vector<int>,
- */
- SearchServer search_server = CreateSearchServer();
- /*
- считываю строку запроса, так как при построении сервера считались первая строка-стоп-слов,
- вторая строка количество документов, и все документы
- */
- string query = ReadLine(); // (9) считываю последнюю строку -- запрос пользователя
- /* (10)
- сюда прилетит итог поисковой выдачи -- топ 5 документов, тут самое интересное: вызывается главный метод!
- */
- vector<Document> answer = search_server.FindTopDocuments(query);
- for (auto [document_id, relevance] : answer)
- { // (14, конец) осталось распаковать ответ и вывести
- cout << "{ document_id = "s << document_id << ", relevance = "s << relevance << " }"s
- << endl;
- }
- }
- /*
- вход:
- a an on the in is has been are with for from have be was
- 4
- a small curly guinea pig with grey hair has been found
- a young 50 year old crocodile wants to make friends
- a strange brown creature was seen in the box of oranges
- a strange animal with big ears is building a house for its friends
- cheburashka with big ears likes oranges
- выход:
- { document_id = 3, relevance = 2 }
- { document_id = 2, relevance = 1 }
- */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement