shushus

Спринт 9. Параллелим методы поисковой системы. Задание 2.

Mar 6th, 2023 (edited)
402
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 29.17 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. main.cpp
  3. -----------------------------------------------------------------------
  4. #include "process_queries.h"
  5. #include "search_server.h"
  6.  
  7. #include <execution>
  8. #include <iostream>
  9. #include <random>
  10. #include <string>
  11. #include <vector>
  12.  
  13. #include "log_duration.h"
  14.  
  15. using namespace std;
  16.  
  17. string GenerateWord(mt19937& generator, int max_length) {
  18.     const int length = uniform_int_distribution(1, max_length)(generator);
  19.     string word;
  20.     word.reserve(length);
  21.     for (int i = 0; i < length; ++i) {
  22.         word.push_back(uniform_int_distribution('a', 'z')(generator));
  23.     }
  24.     return word;
  25. }
  26.  
  27. vector<string> GenerateDictionary(mt19937& generator, int word_count, int max_length) {
  28.     vector<string> words;
  29.     words.reserve(word_count);
  30.     for (int i = 0; i < word_count; ++i) {
  31.         words.push_back(GenerateWord(generator, max_length));
  32.     }
  33.     sort(words.begin(), words.end());
  34.     words.erase(unique(words.begin(), words.end()), words.end());
  35.     return words;
  36. }
  37.  
  38. string GenerateQuery(mt19937& generator, const vector<string>& dictionary, int word_count, double minus_prob = 0) {
  39.     string query;
  40.     for (int i = 0; i < word_count; ++i) {
  41.         if (!query.empty()) {
  42.             query.push_back(' ');
  43.         }
  44.         if (uniform_real_distribution<>(0, 1)(generator) < minus_prob) {
  45.             query.push_back('-');
  46.         }
  47.         query += dictionary[uniform_int_distribution<int>(0, dictionary.size() - 1)(generator)];
  48.     }
  49.     return query;
  50. }
  51.  
  52. vector<string> GenerateQueries(mt19937& generator, const vector<string>& dictionary, int query_count, int max_word_count) {
  53.     vector<string> queries;
  54.     queries.reserve(query_count);
  55.     for (int i = 0; i < query_count; ++i) {
  56.         queries.push_back(GenerateQuery(generator, dictionary, max_word_count));
  57.     }
  58.     return queries;
  59. }
  60.  
  61. template <typename ExecutionPolicy>
  62. void Test(string_view mark, SearchServer search_server, const string& query, ExecutionPolicy&& policy) {
  63.     LOG_DURATION(mark);
  64.     const int document_count = search_server.GetDocumentCount();
  65.     int word_count = 0;
  66.     for (int id = 0; id < document_count; ++id) {
  67.         const auto [words, status] = search_server.MatchDocument(policy, query, id);
  68.         word_count += words.size();
  69.     }
  70.     cout << word_count << endl;
  71. }
  72.  
  73. #define TEST(policy) Test(#policy, search_server, query, execution::policy)
  74.  
  75. int main() {
  76.     mt19937 generator;
  77.  
  78.     const auto dictionary = GenerateDictionary(generator, 1000, 10);
  79.     const auto documents = GenerateQueries(generator, dictionary, 10'000, 70);
  80.  
  81.    const string query = GenerateQuery(generator, dictionary, 500, 0.1);
  82.  
  83.    SearchServer search_server(dictionary[0]);
  84.    for (size_t i = 0; i < documents.size(); ++i) {
  85.        search_server.AddDocument(i, documents[i], DocumentStatus::ACTUAL, {1, 2, 3});
  86.    }
  87.  
  88.    TEST(seq);
  89.    TEST(par);
  90. }
  91. -----------------------------------------------------------------------
  92. document.cpp
  93. -----------------------------------------------------------------------
  94.  
  95. empty
  96.  
  97. -----------------------------------------------------------------------
  98. document.h
  99. -----------------------------------------------------------------------
  100. #pragma once
  101. #include <iostream>
  102.  
  103. struct Document {
  104.    Document() = default;
  105.    Document(int id, double relevance, int rating)
  106.        : id(id)
  107.        , relevance(relevance)
  108.        , rating(rating) {
  109.    }
  110.    int id = 0;
  111.    double relevance = 0.0;
  112.    int rating = 0;
  113. };
  114.  
  115. enum class DocumentStatus {
  116.    ACTUAL,
  117.    IRRELEVANT,
  118.    BANNED,
  119.    REMOVED,
  120. };
  121. -----------------------------------------------------------------------
  122. paginator.h
  123. -----------------------------------------------------------------------
  124. #pragma once
  125. #include <algorithm>
  126. #include <vector>
  127. #include <cassert>
  128. #include <iostream>
  129. #include "document.h"
  130.  
  131. using namespace std::string_literals;
  132.  
  133. template <typename IteratorRanges>
  134. class IteratorRange {
  135. public:
  136.    explicit IteratorRange(IteratorRanges begin, IteratorRanges end) : begin_(begin), end_(end), size_(distance(begin, end)){}
  137.    IteratorRanges begin() const  {
  138.        return begin_;
  139.    }
  140.    IteratorRanges end() const {
  141.        return end_;
  142.    }
  143.    size_t size() const {
  144.        return size_;
  145.    }
  146. private:
  147.    IteratorRanges begin_;
  148.    IteratorRanges end_;
  149.    size_t size_;
  150. };
  151.  
  152. std::ostream& operator<<(std::ostream& out, const Document& document) {
  153.    out << "{ document_id = "s << document.id
  154.        << ", relevance = "s << document.relevance
  155.        << ", rating = "s << document.rating << " }"s;
  156.    return out;
  157. }
  158.  
  159. template <typename To_Out>
  160. std::ostream& operator<<(std::ostream& out, const IteratorRange<To_Out>& sheet) {
  161.    auto helper = sheet.begin();
  162.    while(helper != sheet.end()){
  163.        out<< *helper;
  164.        //out<< "Test";
  165.        ++helper;
  166.    }
  167.    return out;
  168. }
  169.  
  170. template <typename Paginatorr>
  171. class Paginator {
  172. public :
  173.    Paginator(const Paginatorr& result_begin, const Paginatorr& result_end, size_t size_of_sheet){
  174.        auto full_size = distance(result_begin, result_end);
  175.        Paginatorr helper = result_begin;
  176.        for (auto i = 0; i < full_size/size_of_sheet; ++i) {
  177.            sheets.push_back(IteratorRange<Paginatorr>(helper, helper+ size_of_sheet));
  178.            helper=helper+size_of_sheet;
  179.        }
  180.        if (helper!= result_end) {
  181.            sheets.push_back(IteratorRange<Paginatorr>(helper, result_end));
  182.        }
  183.    }
  184.    auto begin() const {
  185.        return sheets.begin();
  186.    }
  187.    auto end() const {
  188.        return sheets.end();
  189.    }
  190.    size_t size() {
  191.        return sheets.size();
  192.    }
  193. private:
  194.    std::vector<IteratorRange<Paginatorr>> sheets;
  195. };
  196.  
  197. template <typename Container>
  198. auto Paginate(const Container& c, size_t page_size) {
  199.    return Paginator(begin(c), end(c), page_size);
  200. }
  201. -----------------------------------------------------------------------
  202. process_queries.cpp
  203. -----------------------------------------------------------------------
  204. #include <execution>
  205. #include <algorithm>
  206. #include <list>
  207.  
  208. #include "process_queries.h"
  209.  
  210. std::vector<std::vector<Document>> ProcessQueries(const SearchServer& search_server,
  211.    const std::vector<std::string>& queries){
  212.    
  213.    std::vector<std::vector<Document>> helper(queries.size());
  214.    std::transform(std::execution::par,
  215.                   queries.begin(),
  216.                   queries.end(),
  217.                   helper.begin(),
  218.                   [&search_server](std::string query){
  219.                        return search_server.FindTopDocuments(query);
  220.                    });
  221.    return helper;
  222. }
  223.  
  224. std::vector<Document> ProcessQueriesJoined(const SearchServer& search_server,
  225.    const std::vector<std::string>& queries){
  226.  
  227.    return std::transform_reduce(std::execution::par,
  228.                                 queries.begin(),
  229.                                 queries.end(),
  230.                                 std::vector<Document>{},
  231.                                 [](std::vector<Document> lhs, std::vector<Document> const& rhs){
  232.                                     lhs.insert(lhs.end(), rhs.begin(), rhs.end());
  233.                                     return lhs;
  234.                                 },            
  235.                                 [&search_server](const std::string& query){
  236.                                     return search_server.FindTopDocuments(query);
  237.                                 });
  238. }
  239. -----------------------------------------------------------------------
  240. process_queries.h
  241. -----------------------------------------------------------------------
  242. #pragma once
  243. #include "search_server.h"
  244. #include <vector>
  245. #include <string>
  246.  
  247. std::vector<std::vector<Document>> ProcessQueries(const SearchServer& search_server,
  248.    const std::vector<std::string>& queries);
  249.  
  250. std::vector<Document> ProcessQueriesJoined(const SearchServer& search_server,
  251.    const std::vector<std::string>& queries);
  252. -----------------------------------------------------------------------
  253. read_input_functions.cpp
  254. -----------------------------------------------------------------------
  255. #include "read_input_functions.h"
  256. #include <iostream>
  257.  
  258. using namespace std::string_literals;
  259.  
  260. std::string ReadLine() {
  261.    std::string s;
  262.    std::getline(std::cin, s);
  263.    return s;
  264. }
  265.  
  266. int ReadLineWithNumber() {
  267.    int result;
  268.    std::cin >> result;
  269.    ReadLine();
  270.    return result;
  271. }
  272. -----------------------------------------------------------------------
  273. read_input_functions.h
  274. -----------------------------------------------------------------------
  275. #pragma once
  276. #include "document.h"
  277. #include <string>
  278.  
  279. std::string ReadLine();
  280. int ReadLineWithNumber();
  281. -----------------------------------------------------------------------
  282. request_queue.cpp
  283. -----------------------------------------------------------------------
  284. #include "request_queue.h"
  285.  
  286. std::vector<Document> RequestQueue::AddFindRequest(const std::string& raw_query, DocumentStatus status) {
  287.    return AddFindRequest(raw_query, [&status](int document_id, DocumentStatus document_status, int rating) {return document_status == status;});
  288. }
  289.    
  290. std::vector<Document> RequestQueue::AddFindRequest(const std::string& raw_query) {
  291.    return AddFindRequest(raw_query, DocumentStatus::ACTUAL);
  292. }
  293.    
  294. int RequestQueue::GetNoResultRequests() const {
  295.    return count_if(requests_.begin(), requests_.end(), [](QueryResult query){return query.query_result == 0;});
  296. }
  297. -----------------------------------------------------------------------
  298. request_queue.h
  299. -----------------------------------------------------------------------
  300. #pragma once
  301. #include "search_server.h"
  302. #include <deque>
  303.  
  304. class RequestQueue {
  305. public:
  306.    RequestQueue(const SearchServer& search_server) : search_request(search_server){}  
  307.    template <typename DocumentPredicate>
  308.    std::vector<Document> AddFindRequest(const std::string& raw_query, DocumentPredicate document_predicate);
  309.    std::vector<Document> AddFindRequest(const std::string& raw_query, DocumentStatus status);
  310.    std::vector<Document> AddFindRequest(const std::string& raw_query);
  311.    int GetNoResultRequests() const;
  312. private:
  313.    struct QueryResult {
  314.        bool query_result;
  315.    };
  316.    const SearchServer& search_request;
  317.    std::deque<QueryResult> requests_;
  318.    const static int min_in_day_ = 1440;
  319. };
  320.  
  321. template <typename DocumentPredicate>
  322. std::vector<Document> RequestQueue::AddFindRequest(const std::string& raw_query, DocumentPredicate document_predicate) {
  323.    std::vector<Document> helper = search_request.FindTopDocuments(raw_query, document_predicate);
  324.  
  325.    QueryResult query;
  326.    query.query_result = (helper.empty()==false);
  327.  
  328.    if (!(requests_.size() < min_in_day_)){
  329.        requests_.pop_front();
  330.    }
  331.    requests_.push_back(query);
  332.    return helper;
  333. }
  334. -----------------------------------------------------------------------
  335. search_server.cpp
  336. -----------------------------------------------------------------------
  337. #include <numeric>
  338. #include "search_server.h"
  339.  
  340. void SearchServer::AddDocument(int document_id,
  341.                               const std::string& document,
  342.                               DocumentStatus status,
  343.                               const std::vector<int>& ratings) {
  344.    
  345.    if ((document_id < 0) || (documents_.count(document_id) > 0)) {
  346.        throw std::invalid_argument("Invalid document ID"s);
  347.    }
  348.    
  349.    const auto words = SplitIntoWordsNoStop(document);
  350.    const double inv_word_count = 1.0 / words.size();
  351.    
  352.    for (const std::string& word : words) {
  353.        ids_of_docs_to_word_freqs_[document_id][word] += inv_word_count;
  354.        word_to_document_freqs_[word][document_id] += inv_word_count;
  355.    }
  356.    
  357.    documents_.emplace(document_id, DocumentData{ComputeAverageRating(ratings), status});
  358.    document_ids_.push_back(document_id);
  359. }
  360.  
  361. std::vector<Document> SearchServer::FindTopDocuments(const std::string& raw_query,
  362.                                                     DocumentStatus status) const {
  363.    return FindTopDocuments(raw_query,
  364.                            [status](int document_id,
  365.                                     DocumentStatus document_status,
  366.                                     int rating) {
  367.                                         return document_status == status;
  368.                                     }
  369.                           );
  370. }
  371.  
  372. std::vector<Document> SearchServer::FindTopDocuments(const std::string& raw_query) const {
  373.    return FindTopDocuments(raw_query,
  374.                            DocumentStatus::ACTUAL);
  375. }
  376.  
  377. int SearchServer::GetDocumentCount() const {
  378.    return documents_.size();
  379. }
  380.  
  381. std::vector<int>::const_iterator SearchServer::begin() const {
  382.    return document_ids_.begin();
  383. }
  384.  
  385. std::vector<int>::const_iterator SearchServer::end() const {
  386.    return document_ids_.end();
  387. }
  388.  
  389. const std::map<std::string, double>& SearchServer::GetWordFrequencies(int document_id) const {
  390.    static const std::map<std::string, double> emptyes;
  391.    return (!ids_of_docs_to_word_freqs_.count(document_id))
  392.            ? emptyes
  393.            : ids_of_docs_to_word_freqs_.at(document_id);
  394. }
  395.  
  396. void SearchServer::RemoveDocument(int document_id) {
  397.    RemoveDocument(std::execution::seq,
  398.                   document_id);
  399. }
  400.  
  401. void SearchServer::RemoveDocument(const std::execution::sequenced_policy&,
  402.                                  int document_id) {
  403.    auto helper = std::find(document_ids_.begin(),
  404.                            document_ids_.end(),
  405.                            document_id);
  406.    
  407.    if (helper == document_ids_.end()) {
  408.        return;
  409.    } else {
  410.        document_ids_.erase(helper);
  411.    }
  412.        
  413.    documents_.erase(document_id);
  414.    std::for_each(word_to_document_freqs_.begin(),
  415.                  word_to_document_freqs_.end(),
  416.                  [&](auto& helper) {
  417.                      helper.second.erase(document_id);
  418.                  });
  419. }
  420.  
  421. void SearchServer::RemoveDocument(const std::execution::parallel_policy&,
  422.                                  int document_id) {
  423.    auto helper = std::find(std::execution::par,
  424.                            document_ids_.begin(),
  425.                            document_ids_.end(),
  426.                            document_id);
  427.    
  428.    if (helper == document_ids_.end()) {
  429.        return;
  430.    } else {
  431.        document_ids_.erase(helper);
  432.    }
  433.  
  434.    documents_.erase(document_id);
  435.    std::for_each(std::execution::par,
  436.                   word_to_document_freqs_.begin(),
  437.                   word_to_document_freqs_.end(),
  438.                   [&](auto& helper) {
  439.                       helper.second.erase(document_id);
  440.                   });
  441. }
  442.  
  443. std::tuple<std::vector<std::string>, DocumentStatus> SearchServer::MatchDocument(const std::string& raw_query,
  444.                                                                                 int document_id) const {
  445.    return MatchDocument(std::execution::seq,
  446.                         raw_query,
  447.                         document_id);
  448. }
  449.  
  450. std::tuple<std::vector<std::string>, DocumentStatus> SearchServer::MatchDocument(const std::execution::sequenced_policy&,
  451.                                                                                 const std::string& raw_query,
  452.                                                                                 int document_id) const {
  453.    
  454.    if ((document_id < 0) || (documents_.count(document_id) <= 0)) {
  455.        throw std::invalid_argument("Non-existent document ID"s);
  456.    }
  457.    
  458.    const auto result = ParseQuery(raw_query, true);
  459.    std::vector<std::string> matched_words;
  460.    
  461.    for (const std::string& word : result.minus_words) {
  462.            if (word_to_document_freqs_.count(word) == 0) {
  463.                continue;
  464.            }
  465.            if (word_to_document_freqs_.at(word).count(document_id)) {
  466.                 return {{}, documents_.at(document_id).status};
  467.            }
  468.        }
  469.    
  470.        for (const std::string& word : result.plus_words) {
  471.            if (word_to_document_freqs_.count(word) == 0) {
  472.                continue;
  473.            }
  474.            if (word_to_document_freqs_.at(word).count(document_id)) {
  475.                matched_words.push_back(word);
  476.            }
  477.        }
  478.  
  479.        return {matched_words, documents_.at(document_id).status};
  480. }
  481.  
  482. std::tuple<std::vector<std::string>, DocumentStatus> SearchServer::MatchDocument(const std::execution::parallel_policy&,
  483.                                                                                 const std::string& raw_query,
  484.                                                                                 int document_id) const {
  485.    if ((document_id < 0) || (documents_.count(document_id) <= 0)) {
  486.        throw std::invalid_argument("Non-existent document ID"s);
  487.    }
  488.    
  489.    const auto result = ParseQuery(raw_query, false);
  490.    std::vector<std::string> matched_words(result.plus_words.size());
  491.  
  492.    const auto check = [this, document_id](const std::string& word) {
  493.        const auto helper = word_to_document_freqs_.find(word);
  494.        return helper!= word_to_document_freqs_.end() &&
  495.                        helper->second.count(document_id);
  496.    };
  497.  
  498.    if (std::any_of(std::execution::par,
  499.                    result.minus_words.begin(),
  500.                    result.minus_words.end(),
  501.                    check)) {
  502.                        return {{}, documents_.at(document_id).status};
  503.    }
  504.    
  505.    auto end = std::copy_if(std::execution::par,
  506.                            result.plus_words.begin(),
  507.                            result.plus_words.end(),
  508.                            matched_words.begin(),
  509.                            check);
  510.    
  511.    std::sort(matched_words.begin(), end);
  512.    end = std::unique(matched_words.begin(), end);
  513.    matched_words.erase(end, matched_words.end());
  514.    
  515.    return {matched_words,
  516.            documents_.at(document_id).status};
  517. }
  518.  
  519. bool SearchServer::IsStopWord(const std::string& word) const {
  520.    return stop_words_.count(word) > 0;
  521. }
  522.  
  523. bool SearchServer::IsValidWord(const std::string& word) {
  524.    return none_of(word.begin(),
  525.                   word.end(),
  526.                   [](char c) {
  527.                       return c >= '\0' && c < ' ';
  528.                   }
  529.    );
  530. }
  531.  
  532. std::vector<std::string> SearchServer::SplitIntoWordsNoStop(const std::string& text) const {
  533.    std::vector<std::string> words;
  534.    for (const std::string& word : SplitIntoWords(text)) {
  535.        if (!IsValidWord(word)) {
  536.            throw std::invalid_argument("Word "s + word + " is invalid"s);
  537.        }
  538.        if (!IsStopWord(word)) {
  539.            words.push_back(word);
  540.        }
  541.    }
  542.    return words;
  543. }
  544.  
  545. int SearchServer::ComputeAverageRating(const std::vector<int>& ratings) {
  546.    if (ratings.empty()) {
  547.        return 0;
  548.    }
  549.    int rating_sum = std::accumulate(ratings.begin(),
  550.                                     ratings.end(),
  551.                                     0);
  552.    return rating_sum /static_cast<int>(ratings.size());
  553. }
  554.  
  555. SearchServer::QueryWord SearchServer::ParseQueryWord(const std::string& text) const {
  556.    if (text.empty()) {
  557.        throw std::invalid_argument("Query word is empty"s);
  558.    }
  559.    
  560.    std::string word = text;
  561.    bool is_minus = false;
  562.    
  563.    if (word[0] == '-') {
  564.        is_minus = true;
  565.        word = word.substr(1);
  566.    }
  567.    
  568.    if (word.empty() || word[0] == '-' || !IsValidWord(word)) {
  569.        throw std::invalid_argument("Query word "s + text + " is invalid");
  570.    }
  571.    return {word, is_minus, IsStopWord(word)};
  572. }
  573.  
  574. SearchServer::Query SearchServer::ParseQuery(const std::string& text,
  575.                                             bool sort) const {
  576.    Query result;
  577.    for (const std::string& word : SplitIntoWords(text)) {
  578.        const auto query_word = ParseQueryWord(word);
  579.        if (!query_word.is_stop) {
  580.            if (query_word.is_minus) {
  581.                result.minus_words.push_back(query_word.data);
  582.            } else {
  583.                result.plus_words.push_back(query_word.data);
  584.            }
  585.        }
  586.    }
  587.    if (sort) {
  588.        std::sort(result.minus_words.begin(),
  589.                  result.minus_words.end());
  590.        std::sort(result.plus_words.begin(),
  591.                  result.plus_words.end());
  592.        
  593.        result.minus_words.erase(std::unique(result.minus_words.begin(),
  594.                                             result.minus_words.end()),
  595.                                             result.minus_words.end());
  596.        result.plus_words.erase(std::unique(result.plus_words.begin(),
  597.                                            result.plus_words.end()),
  598.                                            result.plus_words.end());
  599.    }
  600.    return result;
  601. }
  602.  
  603. double SearchServer::ComputeWordInverseDocumentFreq(const std::string& word) const {
  604.    return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  605. }
  606. -----------------------------------------------------------------------
  607. search_server.h
  608. -----------------------------------------------------------------------
  609. #pragma once
  610. #include <tuple>
  611. #include <algorithm>
  612. #include <cmath>
  613. #include <iostream>
  614. #include <map>
  615. #include <set>
  616. #include <stdexcept>
  617. #include <execution>
  618. #include <string>
  619. #include <vector>
  620. #include "read_input_functions.h"
  621. #include "string_processing.h"
  622. #include "log_duration.h"
  623.  
  624. using namespace std::string_literals;
  625.  
  626. class SearchServer {
  627. public:
  628.    template <typename StringContainer>
  629.    SearchServer(const StringContainer& stop_words);
  630.    SearchServer(const std::string& stop_words_text) : SearchServer(SplitIntoWords(stop_words_text)){}
  631.    
  632.    void AddDocument(int document_id,
  633.                     const std::string& document,
  634.                     DocumentStatus status,
  635.                     const std::vector<int>& ratings);
  636.    
  637.    template <typename DocumentPredicate>
  638.    std::vector<Document> FindTopDocuments(const std::string& raw_query,
  639.                                           DocumentPredicate document_predicate) const;
  640.    std::vector<Document> FindTopDocuments(const std::string& raw_query,
  641.                                           DocumentStatus status) const;
  642.    std::vector<Document> FindTopDocuments(const std::string& raw_query) const;
  643.    
  644.    int GetDocumentCount() const;
  645.    
  646.    std::vector<int>::const_iterator begin() const;
  647.    std::vector<int>::const_iterator end() const;
  648.    
  649.    const std::map<std::string, double>& GetWordFrequencies(int document_id) const;
  650.    
  651.    void RemoveDocument(int document_id);
  652.    void RemoveDocument(const std::execution::sequenced_policy&,
  653.                        int document_id);
  654.    void RemoveDocument(const std::execution::parallel_policy&,
  655.                        int document_id);
  656.    
  657.    std::tuple<std::vector<std::string>, DocumentStatus> MatchDocument(const std::string& raw_query,
  658.                                                                       int document_id) const;
  659.    std::tuple<std::vector<std::string>, DocumentStatus> MatchDocument(const std::execution::sequenced_policy&,
  660.                                                                       const std::string& raw_query,
  661.                                                                       int document_id) const;
  662.    std::tuple<std::vector<std::string>, DocumentStatus> MatchDocument(const std::execution::parallel_policy&,
  663.                                                                       const std::string& raw_query,
  664.                                                                       int document_id) const;    
  665.  
  666. private:
  667.    struct DocumentData {
  668.        int rating;
  669.        DocumentStatus status;
  670.    };
  671.    
  672.    const double EPSILON = 1e-6;
  673.    const int MAX_RESULT_DOCUMENT_COUNT = 5;
  674.    
  675.    const std::set<std::string> stop_words_;
  676.    std::map<std::string, std::map<int, double>> word_to_document_freqs_;
  677.    std::map<int, DocumentData> documents_;
  678.    std::vector<int> document_ids_;
  679.    std::map<int, std::map<std::string, double>> ids_of_docs_to_word_freqs_;
  680.  
  681.    bool IsStopWord(const std::string& word) const;
  682.    static bool IsValidWord(const std::string& word);
  683.    std::vector<std::string> SplitIntoWordsNoStop(const std::string& text) const;
  684.    static int ComputeAverageRating(const std::vector<int>& ratings);
  685.  
  686.    struct QueryWord {
  687.        std::string data;
  688.        bool is_minus;
  689.        bool is_stop;
  690.    };
  691.  
  692.    QueryWord ParseQueryWord(const std::string& text) const;
  693.  
  694.    struct Query {
  695.        std::vector<std::string> plus_words;
  696.        std::vector<std::string> minus_words;
  697.    };
  698.  
  699.    Query ParseQuery(const std::string& text, bool sort) const;
  700.    double ComputeWordInverseDocumentFreq(const std::string& word) const;
  701.  
  702.    template <typename DocumentPredicate>
  703.    std::vector<Document> FindAllDocuments(const Query& query,
  704.                                           DocumentPredicate document_predicate) const;
  705. };
  706.  
  707. template <typename StringContainer>
  708. SearchServer::SearchServer(const StringContainer& stop_words) : stop_words_(MakeUniqueNonEmptyStrings(stop_words)){
  709.    if (!all_of(stop_words_.begin(), stop_words_.end(), IsValidWord)) {
  710.        throw std::invalid_argument("Some of stop words are invalid"s);
  711.    }
  712. }
  713.  
  714. template <typename DocumentPredicate>
  715. std::vector<Document> SearchServer::FindTopDocuments(const std::string& raw_query,
  716.                                                     DocumentPredicate document_predicate) const {
  717.    const auto query = ParseQuery(raw_query, true);
  718.    auto matched_documents = FindAllDocuments(query,
  719.                                              document_predicate);
  720.    sort(matched_documents.begin(), matched_documents.end(),
  721.    [this](const Document& lhs, const Document& rhs) {
  722.        if (std::abs(lhs.relevance - rhs.relevance) < EPSILON) {
  723.            return lhs.rating > rhs.rating;
  724.        } else {
  725.            return lhs.relevance > rhs.relevance;
  726.        }
  727.    });
  728.    if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  729.        matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  730.    }
  731.        return matched_documents;
  732. }
  733.  
  734. template <typename DocumentPredicate>
  735. std::vector<Document> SearchServer::FindAllDocuments(const Query& query,
  736.                                                     DocumentPredicate document_predicate) const {
  737.    std::map<int, double> document_to_relevance;
  738.    for (const std::string& word : query.plus_words) {
  739.        if (word_to_document_freqs_.count(word) == 0) {
  740.            continue;
  741.        }
  742.    const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  743.        for (const auto [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  744.            const auto& document_data = documents_.at(document_id);
  745.            if (document_predicate(document_id, document_data.status, document_data.rating)) {
  746.                document_to_relevance[document_id] += term_freq * inverse_document_freq;
  747.            }
  748.        }
  749.    }
  750.  
  751.    for (const std::string& word : query.minus_words) {
  752.       if (word_to_document_freqs_.count(word) == 0) {
  753.            continue;
  754.        }
  755.        for (const auto [document_id, _] : word_to_document_freqs_.at(word)) {
  756.            document_to_relevance.erase(document_id);
  757.        }
  758.    }
  759.  
  760.    std::vector<Document> matched_documents;
  761.    for (const auto [document_id, relevance] : document_to_relevance) {
  762.        matched_documents.push_back(
  763.            {document_id, relevance, documents_.at(document_id).rating});
  764.    }
  765.    return matched_documents;
  766. }
  767. -----------------------------------------------------------------------
  768. string_processing.cpp
  769. -----------------------------------------------------------------------
  770. #include "string_processing.h"
  771.  
  772. std::vector<std::string> SplitIntoWords(const std::string& text) {
  773.    std::vector<std::string> words;
  774.    std::string word;
  775.    for (const char c : text) {
  776.        if (c == ' ') {
  777.            if (!word.empty()) {
  778.                words.push_back(word);
  779.                word.clear();
  780.            }
  781.        } else {
  782.            word += c;
  783.        }
  784.    }
  785.    if (!word.empty()) {
  786.        words.push_back(word);
  787.    }
  788.    return words;
  789. }
  790. -----------------------------------------------------------------------
  791. string_processing.h
  792. -----------------------------------------------------------------------
  793. #pragma once
  794. #include <set>
  795. #include <vector>
  796. #include <string>
  797.  
  798. std::vector<std::string> SplitIntoWords(const std::string& text);
  799.  
  800. template <typename StringContainer>
  801. std::set<std::string> MakeUniqueNonEmptyStrings(const StringContainer& strings) {
  802.    std::set<std::string> non_empty_strings;
  803.    for (const std::string& str : strings) {
  804.        if (!str.empty()) {
  805.            non_empty_strings.insert(str);
  806.        }
  807.    }
  808.    return non_empty_strings;
  809. }
  810. -----------------------------------------------------------------------
  811. test_example_functions.cpp
  812. -----------------------------------------------------------------------
  813.  
  814. empty
  815.  
  816. -----------------------------------------------------------------------
  817. test_example_functions.h
  818. -----------------------------------------------------------------------
  819.  
  820. empty
  821.  
Advertisement
Add Comment
Please, Sign In to add comment