Advertisement
giGii

пример поиска

Aug 13th, 2022
129
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.21 KB | None | 0 0
  1. #include <algorithm>
  2. #include <iostream>
  3. #include <set>
  4. #include <string>
  5. #include <utility>
  6. #include <vector>
  7.  
  8. using namespace std;
  9.  
  10. const int MAX_RESULT_DOCUMENT_COUNT = 5;
  11.  
  12. string ReadLine()
  13. {
  14.     string s;
  15.     getline(cin, s);
  16.     return s;
  17. }
  18.  
  19. int ReadLineWithNumber()
  20. {
  21.     int result = 0;
  22.     cin >> result;
  23.     ReadLine();
  24.     return result;
  25. }
  26. // (6) разбивает входящую строку на отдельные слова, возвращает вектор слов входящей строки
  27. vector<string> SplitIntoWords(const string &text)
  28. {
  29.     vector<string> words;
  30.     string word;
  31.     for (const char c : text)
  32.     {
  33.         if (c == ' ')
  34.         {
  35.             if (!word.empty())
  36.             {
  37.                 words.push_back(word);
  38.                 word.clear();
  39.             }
  40.         }
  41.         else
  42.         {
  43.             word += c;
  44.         }
  45.     }
  46.     if (!word.empty())
  47.     {
  48.         words.push_back(word);
  49.     }
  50.  
  51.     return words;
  52. }
  53.  
  54. struct Document
  55. {
  56.     int id;
  57.     int relevance;
  58. };
  59.  
  60. bool HasDocumentGreaterRelevance(const Document &lhs, const Document &rhs)
  61. {
  62.     return lhs.relevance > rhs.relevance;
  63. }
  64.  
  65. class SearchServer
  66. {
  67. public:
  68.     /* (7)
  69.     это второй используемый метод-процедура в программе. его задача получить порядковый номер
  70.     документа int document_id, например, 1, и сам документ, например "это очередной документ",
  71.     и наполняет поле-переменную класса vector<DocumentContent> documents_; сам DocumetContent
  72.     так определен (это самописный тип, о нем уже было), что первое его поле id, второе words,
  73.     а сам вектор документов будет заполнен например так:
  74.  
  75.     DocumentContent documents_ = {
  76.         {1, {"это", "очередной", "документ"}},
  77.         {1, {"это", "тоже", "документ"}}
  78.     }
  79.      */
  80.     void AddDocument(int document_id, const string &document)
  81.     {
  82.         const vector<string> words = SplitIntoWordsNoStop(document, stop_words_);
  83.         documents_.push_back({document_id, words});
  84.     }
  85.  
  86.     /* (5)
  87.     это первый вызываемый метод, в него попадает строка стоп слов по типу: "это стоп слово",
  88.     а выходит ничего, потому что тип возвращаемого значения void, кажется, в старые времена
  89.     это называлось процедурой (функция что-то делает и возвращает, процедура просто что-то делает);
  90.  
  91.     эта процедура-метод наполняет поле-переменную класса set<string> stop_words_;
  92.      */
  93.  
  94.     void SetStopWords(const string &text)
  95.     {
  96.         for (const string &word : SplitIntoWords(text))
  97.         {
  98.             stop_words_.insert(word);
  99.         }
  100.     }
  101.  
  102.  
  103.     /* (11)
  104.     метод FindTopDocuments вызывается для выдачи максимум 5 документов, соответствующих исходному
  105.     поисковому запросу; он принимает запрос в виде "это запрос на поиск" -- "сырой" запрос, не разбитый на
  106.     отдельные слова, дальше он их разбивает при помощи функции ParseQuery, объявленной в приватной области
  107.     (в приватной, т.к. она необходима для обслущивания работы методов внутри класса, а не для вызова из функции main);
  108.  
  109.     далее вызывается также приватная функция FindAllDocuments, которая принимает уже разбитый на слова поисковый запрос
  110.     в виде множества слов, входящих в запрос set<string> по типу {"это", "поисковый", "запрос"}; ответ от функции
  111.     FindAllDocuments будет отсортирован с применением компаратора HasDocumentGreaterRelevance и выдан для печати в
  112.     функцию main, откуда и вызывался метод FindTopDocuments
  113.     */
  114.  
  115.  
  116.     vector<Document> FindTopDocuments(const string &raw_query)
  117.     {
  118.         const set<string> query_words = ParseQuery(raw_query);
  119.         auto matched_documents = FindAllDocuments(query_words);
  120.  
  121.         sort(matched_documents.begin(), matched_documents.end(), HasDocumentGreaterRelevance);
  122.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT)
  123.         {
  124.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  125.         }
  126.         return matched_documents;
  127.     }
  128.  
  129. private:
  130.     struct DocumentContent
  131.     {
  132.         int id = 0;
  133.         vector<string> words;
  134.     };
  135.     // (12) разбивает поданную строку на слова, возвращает множество слов, в которое не входят стоп-слова, содержащиеся в строке
  136.     set<string> ParseQuery(const string &query_text)
  137.     {
  138.         set<string> query_words;
  139.         for (const string &word : SplitIntoWordsNoStop(query_text, stop_words_))
  140.         {
  141.             query_words.insert(word);
  142.         }
  143.         return query_words;
  144.     }
  145.     // (8) разбивает поданную строку на слова известной функцией, возвращает вектор строк, в котором нет стоп-слов
  146.     vector<string> SplitIntoWordsNoStop(const string &text, const set<string> &stop_words)
  147.     {
  148.         vector<string> words;
  149.         for (const string &word : SplitIntoWords(text))
  150.         {
  151.             if (stop_words.count(word) == 0)
  152.             {
  153.                 words.push_back(word);
  154.             }
  155.         }
  156.         return words;
  157.     }
  158.  
  159.     /* (13)
  160.     ну и последний штрих -- также приватная функция MatchDocument, которая занимается матчингом конкретного документа
  161.     и поискового запроса; принимает сам документ в виде вестора строк, например vector<string> doc = {"сам", "документ"}
  162.     и поисковый запрос в виде множества слов в виде set<string> query = {"слово", "и", "еще", "слово"}, перебирая слова
  163.     в документе, в итоге вернет число -- сколько слов из поискового запроса попадаются в документе
  164.     */
  165.  
  166.     static int MatchDocument(const vector<string> document, const set<string> &query_words)
  167.     {
  168.         if (query_words.empty())
  169.         {
  170.             return 0;
  171.         }
  172.  
  173.         set<string> matched_words;
  174.         for (const string &word : document)
  175.         {
  176.             if (matched_words.count(word) != 0)
  177.             {
  178.                 continue;
  179.             }
  180.             if (query_words.count(word) != 0)
  181.             {
  182.                 matched_words.insert(word);
  183.             }
  184.         }
  185.         return static_cast<int>(matched_words.size());
  186.     }
  187.  
  188.     /* (12)
  189.     функция FindAllDocuments приватная, она необходима для работы методов класса, поэтому скрывается от внешнего
  190.     пользователя; она примет распарсенный на слова поисковый запрос в виде множества слов, будет брать из поля
  191.     documents_ документы и матчить их при помощи приватной функции MatchDocument; показатель мэтча это пересечение
  192.     множества слов запроса и документа, иначе говоря -- искомая релевантность
  193.     */
  194.     vector<Document> FindAllDocuments(const set<string> &query_words)
  195.     {
  196.         vector<Document> matched_documents;
  197.         for (const auto &document : documents_)
  198.         {
  199.             const int relevance = MatchDocument(document.words, query_words);
  200.             if (relevance > 0)
  201.             {
  202.                 matched_documents.push_back({document.id, relevance});
  203.             }
  204.         }
  205.         return matched_documents;
  206.     }
  207.  
  208.     vector<DocumentContent> documents_;
  209.     set<string> stop_words_;
  210. };
  211.  
  212. SearchServer CreateSearchServer()
  213. {
  214.     /* (2)
  215.     при конструировании черного-ящика-поискового-сервера, который будет на ввод пользователя выводить
  216.     документы согласно их релевантности запросу, считывается строка стоп-слов
  217.     */
  218.     string stop_words = ReadLine();
  219.  
  220.     /* (3)
  221.     затем создается поисковый сервер -- переменная server типа SearchServer.
  222.     SearchServer это "класс" -- объект с данными и методами доступа к данным, разработан выше
  223.     */
  224.  
  225.     SearchServer server;
  226.  
  227.     /* (4)
  228.     здесь сервер через метод заполнит одно из двух своих полей -- поле стоп-слов, это вектор строк,
  229.     который имеет вид set<string> stop_words_;
  230.     */
  231.  
  232.     server.SetStopWords(stop_words);
  233.  
  234.     /*
  235.     здесь считается число документов, и в цикле через метод заполнится второе поле -- поле документов,
  236.     которое имеет вид vector<DocumentContent> documents_;
  237.  
  238.     коротко это вектор документов. DocumentContent это так называемая структура, это по сути
  239.     самописный тип данных в котором можно к полям обращаться через точку по имени. поля это
  240.     переменные, хранящие что-то (данные);
  241.    
  242.     в данном случае случае структура DocumentContent имеет вид:
  243.  
  244.     struct DocumentContent
  245.     {
  246.         int id = 0;
  247.         vector<string> words;
  248.     };
  249.  
  250.     первое переданное значение будет ожидаться как целое число, к нему можно обратиться по имени id, а
  251.     означает оно номер документа;
  252.     второе переданное значение будет ожидаться как вектор строк, к нему можно будет обратиться
  253.     по имени words, а означать оно будет слова, на которые по пробелам побит документ из базы данных,
  254.     по которй ведется поиск релевантных документов
  255.  
  256.     эта структура определяется в приватной области класса, она просто делает код более читаемым.
  257.     например, определив
  258.    
  259.     DocumentContent my_document = {1, {"abacaba", "abcbdbba", "ababababa"}};
  260.  
  261.     я теперь могу написать
  262.  
  263.     cout << "первое слово документа " << my_document.id << " -- " << my_document.words[0] << endl;
  264.  
  265.     и выведется: первое слово документа 1 -- abacaba
  266.     */
  267.  
  268.     int count_docs = ReadLineWithNumber();
  269.     for (int doc_id = 0; doc_id < count_docs; ++doc_id)
  270.     {
  271.         string document = ReadLine();
  272.         server.AddDocument(doc_id, document);
  273.     }
  274.  
  275.     return server;
  276. }
  277.  
  278. int main()
  279. {
  280.     /* (1)
  281.     делаю поисковый сервер. SearchServer это как тип int, vector<string> и тд. только
  282.     называется от классом и является черным ящиком, в котором хранится инфа в виде "полей" класса,
  283.     и интерфейсы взаимодействия с классом, которые называются методы. методы это по сути функции, но
  284.     специализирующиеся в работе только над полями класса; поля класса это переменные какого-то типа,
  285.     например set<string>, vector<int>,
  286.     */
  287.     SearchServer search_server = CreateSearchServer();
  288.     /*
  289.     считываю строку запроса, так как при построении сервера считались первая строка-стоп-слов,
  290.     вторая строка количество документов, и все документы
  291.     */
  292.     string query = ReadLine(); // (9) считываю последнюю строку -- запрос пользователя
  293.  
  294.     /* (10)
  295.     сюда прилетит итог поисковой выдачи -- топ 5 документов, тут самое интересное: вызывается главный метод!
  296.     */
  297.  
  298.     vector<Document> answer = search_server.FindTopDocuments(query);
  299.  
  300.     for (auto [document_id, relevance] : answer)
  301.     { // (14, конец) осталось распаковать ответ и вывести
  302.         cout << "{ document_id = "s << document_id << ", relevance = "s << relevance << " }"s
  303.              << endl;
  304.     }
  305. }
  306.  
  307. /*
  308. вход:
  309.  
  310. a an on the in is has been are with for from have be was
  311. 4
  312. a small curly guinea pig with grey hair has been found
  313. a young 50 year old crocodile wants to make friends
  314. a strange brown creature was seen in the box of oranges
  315. a strange animal with big ears is building a house for its friends
  316. cheburashka with big ears likes oranges
  317.  
  318. выход:
  319. { document_id = 3, relevance = 2 }
  320. { document_id = 2, relevance = 1 }
  321. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement