shushus

Спринт 9. Параллелим поиск документов.

Mar 8th, 2023 (edited)
555
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 41.14 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. main.cpp
  3. -----------------------------------------------------------------------
  4. #include "search_server.h"
  5. #include "log_duration.h"
  6. #include "process_queries.h"
  7. #include <execution>
  8. #include <iostream>
  9. #include <random>
  10. #include <string>
  11. #include <vector>
  12.  
  13. using namespace std;
  14.  
  15. string GenerateWord(mt19937& generator, int max_length) {
  16.     const int length = uniform_int_distribution(1, max_length)(generator);
  17.     string word;
  18.     word.reserve(length);
  19.     for (int i = 0; i < length; ++i) {
  20.         word.push_back(uniform_int_distribution('a', 'z')(generator));
  21.     }
  22.     return word;
  23. }
  24.  
  25. vector<string> GenerateDictionary(mt19937& generator, int word_count, int max_length) {
  26.     vector<string> words;
  27.     words.reserve(word_count);
  28.     for (int i = 0; i < word_count; ++i) {
  29.         words.push_back(GenerateWord(generator, max_length));
  30.     }
  31.     words.erase(unique(words.begin(), words.end()), words.end());
  32.     return words;
  33. }
  34.  
  35. string GenerateQuery(mt19937& generator, const vector<string>& dictionary, int word_count, double minus_prob = 0) {
  36.     string query;
  37.     for (int i = 0; i < word_count; ++i) {
  38.         if (!query.empty()) {
  39.             query.push_back(' ');
  40.         }
  41.         if (uniform_real_distribution<>(0, 1)(generator) < minus_prob) {
  42.             query.push_back('-');
  43.         }
  44.         query += dictionary[uniform_int_distribution<int>(0, dictionary.size() - 1)(generator)];
  45.     }
  46.     return query;
  47. }
  48.  
  49. vector<string> GenerateQueries(mt19937& generator, const vector<string>& dictionary, int query_count, int max_word_count) {
  50.     vector<string> queries;
  51.     queries.reserve(query_count);
  52.     for (int i = 0; i < query_count; ++i) {
  53.         queries.push_back(GenerateQuery(generator, dictionary, max_word_count));
  54.     }
  55.     return queries;
  56. }
  57.  
  58. template <typename ExecutionPolicy>
  59. void Test(string_view mark, const SearchServer& search_server, const vector<string>& queries, ExecutionPolicy&& policy) {
  60.     LOG_DURATION(mark);
  61.     double total_relevance = 0;
  62.     for (const string_view query : queries) {
  63.         for (const auto& document : search_server.FindTopDocuments(policy, query)) {
  64.             total_relevance += document.relevance;
  65.         }
  66.     }
  67.     cout << total_relevance << endl;
  68. }
  69.  
  70. #define TEST(policy) Test(#policy, search_server, queries, execution::policy)
  71.  
  72. int main() {
  73.     mt19937 generator;
  74.     const auto dictionary = GenerateDictionary(generator, 1000, 10);
  75.     const auto documents = GenerateQueries(generator, dictionary, 10'000, 70);
  76.    SearchServer search_server(dictionary[0]);
  77.    for (size_t i = 0; i < documents.size(); ++i) {
  78.        search_server.AddDocument(i, documents[i], DocumentStatus::ACTUAL, {1, 2, 3});
  79.    }
  80.    const auto queries = GenerateQueries(generator, dictionary, 100, 70);
  81.    TEST(seq);
  82.    TEST(par);
  83. }
  84. -----------------------------------------------------------------------
  85. document.cpp
  86. -----------------------------------------------------------------------
  87.  
  88. empty
  89.  
  90. -----------------------------------------------------------------------
  91. document.h
  92. -----------------------------------------------------------------------
  93. #pragma once
  94. #include <iostream>
  95.  
  96. struct Document {
  97.    Document() = default;
  98.    Document(int id, double relevance, int rating)
  99.        : id(id)
  100.        , relevance(relevance)
  101.        , rating(rating) {
  102.    }
  103.    int id = 0;
  104.    double relevance = 0.0;
  105.    int rating = 0;
  106. };
  107.  
  108. enum class DocumentStatus {
  109.    ACTUAL,
  110.    IRRELEVANT,
  111.    BANNED,
  112.    REMOVED,
  113. };
  114. -----------------------------------------------------------------------
  115. paginator.h
  116. -----------------------------------------------------------------------
  117. #pragma once
  118. #include <algorithm>
  119. #include <vector>
  120. #include <cassert>
  121. #include <iostream>
  122. #include "document.h"
  123.  
  124. using namespace std::string_literals;
  125.  
  126. template <typename IteratorRanges>
  127. class IteratorRange {
  128. public:
  129.    explicit IteratorRange(IteratorRanges begin, IteratorRanges end) : begin_(begin),
  130.                                                                       end_(end),
  131.                                                                       size_(distance(begin, end)){}
  132.    
  133.    IteratorRanges begin() const  {
  134.        return begin_;
  135.    }
  136.    
  137.    IteratorRanges end() const {
  138.        return end_;
  139.    }
  140.    
  141.    size_t size() const {
  142.        return size_;
  143.    }
  144.    
  145. private:
  146.    IteratorRanges begin_;
  147.    IteratorRanges end_;
  148.    size_t size_;
  149. };
  150.  
  151. std::ostream& operator<<(std::ostream& out, const Document& document) {
  152.    out << "{ document_id = "s << document.id
  153.        << ", relevance = "s << document.relevance
  154.        << ", rating = "s << document.rating << " }"s;
  155.    return out;
  156. }
  157.  
  158. template <typename To_Out>
  159. std::ostream& operator<<(std::ostream& out, const IteratorRange<To_Out>& sheet) {
  160.    auto helper = sheet.begin();
  161.    while(helper != sheet.end()) {
  162.        out<< *helper;
  163.        ++helper;
  164.    }
  165.    return out;
  166. }
  167.  
  168. template <typename Paginatorr>
  169. class Paginator {
  170. public :
  171.    Paginator(const Paginatorr& result_begin, const Paginatorr& result_end, size_t size_of_sheet) {
  172.    
  173.        auto full_size = distance(result_begin, result_end);
  174.        Paginatorr helper = result_begin;
  175.        
  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.        
  181.        if (helper!= result_end) {
  182.            sheets.push_back(IteratorRange<Paginatorr>(helper, result_end));
  183.        }
  184.    }
  185.    
  186.    auto begin() const {
  187.        return sheets.begin();
  188.    }
  189.    
  190.    auto end() const {
  191.        return sheets.end();
  192.    }
  193.    
  194.    size_t size() {
  195.        return sheets.size();
  196.    }
  197.    
  198. private:
  199.    std::vector<IteratorRange<Paginatorr>> sheets;
  200. };
  201.  
  202. template <typename Container>
  203. auto Paginate(const Container& c, size_t page_size) {
  204.    return Paginator(begin(c),
  205.                     end(c),
  206.                     page_size);
  207. }
  208. -----------------------------------------------------------------------
  209. process_queries.cpp
  210. -----------------------------------------------------------------------
  211. #include <execution>
  212. #include <algorithm>
  213. #include <list>
  214.  
  215. #include "process_queries.h"
  216.  
  217. std::vector<std::vector<Document>> ProcessQueries(const SearchServer& search_server,
  218.                                                  const std::vector<std::string>& queries) {
  219.    std::vector<std::vector<Document>> helper(queries.size());
  220.    std::transform(std::execution::par,
  221.                   queries.begin(),
  222.                   queries.end(),
  223.                   helper.begin(),
  224.                   [&search_server](auto query){
  225.                        return search_server.FindTopDocuments(query);
  226.                   });
  227.    return helper;
  228. }
  229.  
  230. std::vector<Document> ProcessQueriesJoined(const SearchServer& search_server,
  231.                                           const std::vector<std::string>& queries) {
  232.    return std::transform_reduce(std::execution::par,
  233.                                 queries.begin(),
  234.                                 queries.end(),
  235.                                 std::vector<Document>{},
  236.                                 [](std::vector<Document> lhs, std::vector<Document> const& rhs){
  237.                                     lhs.insert(lhs.end(), rhs.begin(), rhs.end());
  238.                                     return lhs;
  239.                                 },            
  240.                                 [&search_server](auto query){
  241.                                     return search_server.FindTopDocuments(query);
  242.                                 });
  243. }
  244. -----------------------------------------------------------------------
  245. process_queries.h
  246. -----------------------------------------------------------------------
  247. #pragma once
  248. #include "search_server.h"
  249. #include <vector>
  250. #include <string>
  251.  
  252. std::vector<std::vector<Document>> ProcessQueries(const SearchServer& search_server,
  253.    const std::vector<std::string>& queries);
  254.  
  255. std::vector<Document> ProcessQueriesJoined(const SearchServer& search_server,
  256.    const std::vector<std::string>& queries);
  257. -----------------------------------------------------------------------
  258. read_input_functions.cpp
  259. -----------------------------------------------------------------------
  260. #include "read_input_functions.h"
  261. #include <iostream>
  262.  
  263. using namespace std::string_literals;
  264.  
  265. std::string ReadLine() {
  266.    std::string s;
  267.    std::getline(std::cin, s);
  268.    return s;
  269. }
  270.  
  271. int ReadLineWithNumber() {
  272.    int result;
  273.    std::cin >> result;
  274.    ReadLine();
  275.    return result;
  276. }
  277. -----------------------------------------------------------------------
  278. read_input_functions.h
  279. -----------------------------------------------------------------------
  280. #pragma once
  281. #include "document.h"
  282. #include <string>
  283.  
  284. std::string ReadLine();
  285. int ReadLineWithNumber();
  286. -----------------------------------------------------------------------
  287. request_queue.cpp
  288. -----------------------------------------------------------------------
  289. #include "request_queue.h"
  290.  
  291. std::vector<Document> RequestQueue::AddFindRequest(std::string_view raw_query,
  292.                                                   DocumentStatus status) {
  293.    return AddFindRequest(raw_query,
  294.                          [&status](int document_id,
  295.                                    DocumentStatus document_status,
  296.                                    int rating) {
  297.                                        return document_status == status;
  298.                                    });
  299. }
  300.    
  301. std::vector<Document> RequestQueue::AddFindRequest(std::string_view raw_query) {
  302.    
  303.    return AddFindRequest(raw_query,
  304.                          DocumentStatus::ACTUAL);
  305. }
  306.    
  307. int RequestQueue::GetNoResultRequests() const {
  308.    return count_if(requests_.begin(),
  309.                    requests_.end(),
  310.                    [](QueryResult query) {
  311.                        return query.query_result == 0;
  312.                    });
  313. }
  314. -----------------------------------------------------------------------
  315. request_queue.h
  316. -----------------------------------------------------------------------
  317. #pragma once
  318. #include "search_server.h"
  319. #include <deque>
  320.  
  321. class RequestQueue {
  322. public:
  323.    RequestQueue(const SearchServer& search_server) : search_request(search_server){}
  324.    
  325.    template <typename DocumentPredicate>
  326.    std::vector<Document> AddFindRequest(std::string_view raw_query, DocumentPredicate document_predicate);
  327.    std::vector<Document> AddFindRequest(std::string_view raw_query, DocumentStatus status);
  328.    std::vector<Document> AddFindRequest(std::string_view raw_query);
  329.    
  330.    int GetNoResultRequests() const;
  331. private:
  332.    struct QueryResult {
  333.        bool query_result;
  334.    };
  335.    
  336.    const SearchServer& search_request;
  337.    std::deque<QueryResult> requests_;
  338.    const static int min_in_day_ = 1440;
  339. };
  340.  
  341. template <typename DocumentPredicate>
  342. std::vector<Document> RequestQueue::AddFindRequest(std::string_view raw_query,
  343.                                                   DocumentPredicate document_predicate) {
  344.    std::vector<Document> helper = search_request.FindTopDocuments(raw_query,
  345.                                                                   document_predicate);
  346.    QueryResult query;
  347.    query.query_result = (helper.empty()==false);
  348.    
  349.    if (!(requests_.size() < min_in_day_)){
  350.        requests_.pop_front();
  351.    }
  352.    
  353.    requests_.push_back(query);
  354.    return helper;
  355. }
  356. -----------------------------------------------------------------------
  357. search_server.cpp
  358. -----------------------------------------------------------------------
  359. #include <numeric>
  360. #include "search_server.h"
  361.  
  362. void SearchServer::AddDocument(int document_id,
  363.                               std::string_view document,
  364.                               DocumentStatus status,
  365.                               const std::vector<int>& ratings) {
  366.    
  367.    if ((document_id < 0) || (documents_.count(document_id) > 0)) {
  368.        throw std::invalid_argument("Invalid document ID"s);
  369.    }
  370.    
  371.    auto [doc_id_, doc_data_] = documents_.emplace(document_id,
  372.                                                   DocumentData{
  373.                                                       std::string(document),
  374.                                                       ComputeAverageRating(ratings),
  375.                                                       status
  376.                                                    });
  377.    document_ids_.push_back(document_id);
  378.    
  379.    const auto words = SplitIntoWordsNoStop(doc_id_->second.data_string_);
  380.    
  381.    const double inv_word_count = 1.0 / words.size();
  382.    
  383.    for (auto word : words) {
  384.        word_to_document_freqs_[word][document_id] += inv_word_count;
  385.        ids_of_docs_to_word_freqs_[document_id][word] += inv_word_count;
  386.    }
  387. }
  388.  
  389. std::vector<Document> SearchServer::FindTopDocuments(std::string_view raw_query,
  390.                                                     DocumentStatus status) const {
  391.    return FindTopDocuments(std::execution::seq, raw_query, status);
  392. }
  393.  
  394. std::vector<Document> SearchServer::FindTopDocuments(const std::execution::sequenced_policy&,
  395.                                                     std::string_view raw_query,
  396.                                                     DocumentStatus status) const {
  397.    return FindTopDocuments(std::execution::seq,
  398.                            raw_query,
  399.                            [status](int document_id,
  400.                                     DocumentStatus document_status,
  401.                                     int rating) {
  402.                                         return document_status == status;
  403.                                     }
  404.                           );
  405. }
  406.  
  407. std::vector<Document> SearchServer::FindTopDocuments(const std::execution::parallel_policy&,
  408.                                                     std::string_view raw_query,
  409.                                                     DocumentStatus status) const {
  410.    return FindTopDocuments(std::execution::par,
  411.                            raw_query,
  412.                            [status](int document_id,
  413.                                     DocumentStatus document_status,
  414.                                     int rating) {
  415.                                         return document_status == status;
  416.                                     }
  417.                           );
  418. }
  419.  
  420. std::vector<Document> SearchServer::FindTopDocuments(std::string_view raw_query) const {
  421.    return FindTopDocuments(std::execution::seq,
  422.                            raw_query,
  423.                            DocumentStatus::ACTUAL);
  424. }
  425.  
  426. std::vector<Document> SearchServer::FindTopDocuments(const std::execution::sequenced_policy&,
  427.                                                     std::string_view raw_query) const {
  428.    return FindTopDocuments(std::execution::seq,
  429.                            raw_query,
  430.                            DocumentStatus::ACTUAL);
  431. }
  432.  
  433. std::vector<Document> SearchServer::FindTopDocuments(const std::execution::parallel_policy&,
  434.                                                     std::string_view raw_query) const {
  435.    return FindTopDocuments(std::execution::par,
  436.                            raw_query,
  437.                            DocumentStatus::ACTUAL);
  438. }
  439.  
  440. int SearchServer::GetDocumentCount() const {
  441.    return documents_.size();
  442. }
  443.  
  444. std::vector<int>::const_iterator SearchServer::begin() const {
  445.    return document_ids_.begin();
  446. }
  447.  
  448. std::vector<int>::const_iterator SearchServer::end() const {
  449.    return document_ids_.end();
  450. }
  451.  
  452. const std::map<std::string_view, double>& SearchServer::GetWordFrequencies(int document_id) const {
  453.    static const std::map<std::string_view, double> emptyes;
  454.    return (!ids_of_docs_to_word_freqs_.count(document_id))
  455.            ? emptyes
  456.            : ids_of_docs_to_word_freqs_.at(document_id);
  457. }
  458.  
  459. void SearchServer::RemoveDocument(int document_id) {
  460.    RemoveDocument(std::execution::seq,
  461.                   document_id);
  462. }
  463.  
  464. void SearchServer::RemoveDocument(const std::execution::sequenced_policy&,
  465.                                  int document_id) {
  466.    auto helper = std::find(
  467.                            document_ids_.begin(),
  468.                            document_ids_.end(),
  469.                            document_id);
  470.    
  471.    if (helper == document_ids_.end()) {
  472.        return;
  473.    } else {
  474.        document_ids_.erase(helper);
  475.    }
  476.        
  477.    documents_.erase(document_id);
  478.    
  479.    std::for_each(word_to_document_freqs_.begin(),
  480.                  word_to_document_freqs_.end(),
  481.                  [&](auto& helper) {
  482.                      helper.second.erase(document_id);
  483.                  });
  484. }
  485.  
  486. void SearchServer::RemoveDocument(const std::execution::parallel_policy&,
  487.                                  int document_id) {
  488.    auto helper = std::find(std::execution::par,
  489.                            document_ids_.begin(),
  490.                            document_ids_.end(),
  491.                            document_id);
  492.    
  493.    if (helper == document_ids_.end()) {
  494.        return;
  495.    } else {
  496.        document_ids_.erase(helper);
  497.    }
  498.  
  499.    documents_.erase(document_id);
  500.    
  501.    std::for_each(std::execution::par,
  502.        word_to_document_freqs_.begin(),
  503.                   word_to_document_freqs_.end(),
  504.                   [&](auto& helper) {
  505.                       helper.second.erase(document_id);
  506.                   });
  507. }
  508.  
  509. std::tuple<std::vector<std::string_view>, DocumentStatus> SearchServer::MatchDocument(std::string_view raw_query,
  510.                                                                                      int document_id) const {
  511.    return MatchDocument(std::execution::seq,
  512.                         raw_query,
  513.                         document_id);
  514. }
  515.  
  516. std::tuple<std::vector<std::string_view>, DocumentStatus> SearchServer::MatchDocument(const std::execution::sequenced_policy&,
  517.                                                                                      std::string_view raw_query,
  518.                                                                                      int document_id) const {
  519.  
  520.    if ((document_id < 0) || (documents_.count(document_id) <= 0)) {
  521.        throw std::invalid_argument("Non-existent document ID"s);
  522.    }
  523.    
  524.    const auto result = ParseQuery(raw_query);
  525.    std::vector<std::string_view> matched_words;
  526.    
  527.    for (auto word : result.minus_words) {
  528.        if (word_to_document_freqs_.count(word) == 0) {
  529.            continue;
  530.        }
  531.        if (word_to_document_freqs_.at(word).count(document_id)) {
  532.            return {{}, documents_.at(document_id).status};
  533.        }
  534.    }
  535.    
  536.    for (auto word : result.plus_words) {
  537.        if (word_to_document_freqs_.count(word) == 0) {
  538.            continue;
  539.        }
  540.        if (word_to_document_freqs_.at(word).count(document_id)) {
  541.            matched_words.push_back(word);
  542.        }
  543.    }
  544.  
  545.    return {matched_words,
  546.            documents_.at(document_id).status};
  547. }
  548.  
  549. std::tuple<std::vector<std::string_view>, DocumentStatus> SearchServer::MatchDocument(const std::execution::parallel_policy&,
  550.                                                                                      std::string_view raw_query,
  551.                                                                                      int document_id) const {
  552.    
  553.    if ((document_id < 0) || (documents_.count(document_id) <= 0)) {
  554.        throw std::invalid_argument("Non-existent document ID"s);
  555.    }
  556.    
  557.    const auto& result = ParseQuery(raw_query);    
  558.  
  559.    const auto& checker = [this, document_id](std::string_view word) {
  560.        const auto helper = word_to_document_freqs_.find(word);
  561.        return helper!= word_to_document_freqs_.end() &&
  562.                        helper->second.count(document_id);        
  563.    };
  564.  
  565.    if (std::any_of(std::execution::par,
  566.                    result.minus_words.begin(),
  567.                    result.minus_words.end(),
  568.                    checker)) {
  569.        return {{}, documents_.at(document_id).status};
  570.    }
  571.    
  572.    std::vector<std::string_view> matched_words(result.plus_words.size());
  573.    
  574.    auto end = std::copy_if(std::execution::par,
  575.                            result.plus_words.begin(),
  576.                            result.plus_words.end(),
  577.                            matched_words.begin(),
  578.                            checker);
  579.    
  580.    std::sort(matched_words.begin(), end);
  581.    end = std::unique(std::execution::par,
  582.                      matched_words.begin(),
  583.                      end);
  584.    
  585.    matched_words.erase(end, matched_words.end());
  586.    return {matched_words,
  587.            documents_.at(document_id).status};
  588. }
  589.  
  590. bool SearchServer::IsStopWord(std::string_view word) const {
  591.    return stop_words_.count(word) > 0;
  592. }
  593.  
  594. bool SearchServer::IsValidWord(std::string_view word) {
  595.    return std::none_of(word.begin(),
  596.                        word.end(),
  597.                        [](char c) {
  598.                            return c >= '\0' && c < ' ';
  599.                        }
  600.    );
  601. }
  602.  
  603. std::vector<std::string_view> SearchServer::SplitIntoWordsNoStop(std::string_view text) const {
  604.    std::vector<std::string_view> words;
  605.    
  606.    for (std::string_view& word : SplitIntoWords(text)) {        
  607.        if (!IsValidWord(word)) {
  608.            throw std::invalid_argument("Word "s + std::string(word) + " is invalid"s);
  609.        }
  610.        if (!IsStopWord(word)) {
  611.            words.push_back(word);
  612.        }
  613.    }
  614.    return words;
  615. }
  616.  
  617. int SearchServer::ComputeAverageRating(const std::vector<int>& ratings) {
  618.    if (ratings.empty()) {
  619.        return 0;
  620.    }
  621.    int rating_sum = std::accumulate(ratings.begin(),
  622.                                     ratings.end(),
  623.                                     0);
  624.    return rating_sum /static_cast<int>(ratings.size());
  625. }
  626.  
  627. SearchServer::QueryWord SearchServer::ParseQueryWord(std::string_view& text) const {
  628.    if (text.empty()) {
  629.        throw std::invalid_argument("Query word is empty"s);
  630.    }
  631.    
  632.    bool is_minus = false;
  633.    
  634.    if (text[0] == '-') {
  635.        is_minus = true;
  636.        text = text.substr(1);
  637.    }
  638.    
  639.    if (text.empty() || text[0] == '-' || !IsValidWord(text)) {
  640.        throw std::invalid_argument("Query word "s + std::string(text) + " is invalid");
  641.    }
  642.    return {text, is_minus, IsStopWord(text)};
  643. }
  644.  
  645. SearchServer::Query SearchServer::ParseQuery(std::string_view& text) const {
  646.    Query result;
  647.    
  648.    for (std::string_view& word : SplitIntoWords(text)) {
  649.        const auto query_word = ParseQueryWord(word);
  650.        if (!query_word.is_stop) {
  651.            if (query_word.is_minus) {
  652.                result.minus_words.push_back(query_word.data);
  653.            } else {
  654.                result.plus_words.push_back(query_word.data);
  655.            }
  656.        }
  657.    }
  658.  
  659.    std::sort(std::execution::par,
  660.              result.minus_words.begin(),
  661.              result.minus_words.end());
  662.    std::sort(std::execution::par,
  663.              result.plus_words.begin(),
  664.              result.plus_words.end());
  665.  
  666.    result.minus_words.erase(std::unique(result.minus_words.begin(),
  667.                                         result.minus_words.end()),
  668.                             result.minus_words.end());
  669.    result.plus_words.erase(std::unique(result.plus_words.begin(),
  670.                                        result.plus_words.end()),
  671.                            result.plus_words.end());
  672.  
  673.    return result;
  674. }
  675.  
  676. double SearchServer::ComputeWordInverseDocumentFreq(std::string_view& word) const {
  677.    return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  678. }
  679. -----------------------------------------------------------------------
  680. search_server.h
  681. -----------------------------------------------------------------------
  682. #pragma once
  683. #include <tuple>
  684. #include <algorithm>
  685. #include <cmath>
  686. #include <iostream>
  687. #include <map>
  688. #include <set>
  689. #include <stdexcept>
  690. #include <execution>
  691. #include <string>
  692. #include <vector>
  693. #include <type_traits>
  694. #include <random>
  695. #include <future>  
  696. #include "concurrent_map.h"
  697. #include "read_input_functions.h"
  698. #include "string_processing.h"
  699. #include "log_duration.h"
  700.  
  701. using namespace std::string_literals;
  702.  
  703. class SearchServer {
  704. public:
  705.    template <typename StringContainer>
  706.    SearchServer(const StringContainer& stop_words);
  707.    SearchServer(const std::string& stop_words_text) : SearchServer(SplitIntoWords(stop_words_text)){}
  708.    SearchServer(std::string_view& stop_words_text) : SearchServer(SplitIntoWords(stop_words_text)){}
  709.    SearchServer() = default;
  710.    
  711.    void AddDocument(int document_id,
  712.                     std::string_view document,
  713.                     DocumentStatus status,
  714.                     const std::vector<int>& ratings);
  715.    
  716.    template <typename DocumentPredicate>
  717.    std::vector<Document> FindTopDocuments(std::string_view raw_query,
  718.                                           DocumentPredicate document_predicate) const;
  719.    template <typename DocumentPredicate>
  720.    std::vector<Document> FindTopDocuments(const std::execution::sequenced_policy&,
  721.                                           std::string_view raw_query,
  722.                                           DocumentPredicate document_predicate) const;
  723.    template <typename DocumentPredicate>
  724.    std::vector<Document> FindTopDocuments(const std::execution::parallel_policy&,
  725.                                           std::string_view raw_query,
  726.                                           DocumentPredicate document_predicate) const;
  727.    
  728.    std::vector<Document> FindTopDocuments(std::string_view raw_query,
  729.                                           DocumentStatus status) const;
  730.    std::vector<Document> FindTopDocuments(const std::execution::sequenced_policy&,
  731.                                           std::string_view raw_query,
  732.                                           DocumentStatus status) const;
  733.    std::vector<Document> FindTopDocuments(const std::execution::parallel_policy&,
  734.                                           std::string_view raw_query,
  735.                                           DocumentStatus status) const;
  736.        
  737.        
  738.    std::vector<Document> FindTopDocuments(std::string_view raw_query) const;
  739.    std::vector<Document> FindTopDocuments(const std::execution::sequenced_policy&,
  740.                                           std::string_view raw_query) const;
  741.    std::vector<Document> FindTopDocuments(const std::execution::parallel_policy&,
  742.                                           std::string_view raw_query) const;
  743.    
  744.    int GetDocumentCount() const;
  745.    
  746.    std::vector<int>::const_iterator begin() const;
  747.    std::vector<int>::const_iterator end() const;
  748.    
  749.    const std::map<std::string_view, double>& GetWordFrequencies(int document_id) const;
  750.    
  751.    void RemoveDocument(int document_id);
  752.    void RemoveDocument(const std::execution::sequenced_policy&,
  753.                        int document_id);
  754.    void RemoveDocument(const std::execution::parallel_policy&,
  755.                        int document_id);
  756.    
  757.    std::tuple<std::vector<std::string_view>, DocumentStatus> MatchDocument(std::string_view raw_query,
  758.                                                                       int document_id) const;
  759.    std::tuple<std::vector<std::string_view>, DocumentStatus> MatchDocument(const std::execution::sequenced_policy&,
  760.                                                                       std::string_view raw_query,
  761.                                                                       int document_id) const;
  762.    std::tuple<std::vector<std::string_view>, DocumentStatus> MatchDocument(const std::execution::parallel_policy&,
  763.                                                                       std::string_view raw_query,
  764.                                                                       int document_id) const;    
  765.  
  766. private:
  767.    struct DocumentData {
  768.        std::string data_string_;
  769.        int rating;
  770.        DocumentStatus status;
  771.    };
  772.    
  773.    const double EPSILON = 1e-6;
  774.    const int MAX_RESULT_DOCUMENT_COUNT = 5;
  775.    
  776.    const std::set<std::string, std::less<>> stop_words_;
  777.    
  778.    std::map<std::string_view, std::map<int, double>> word_to_document_freqs_;
  779.    std::map<int, std::map<std::string_view, double>> ids_of_docs_to_word_freqs_;
  780.    
  781.    std::map<int, DocumentData> documents_;
  782.    std::vector<int> document_ids_;
  783.  
  784.    bool IsStopWord(std::string_view word) const;
  785.    static bool IsValidWord(std::string_view word);
  786.    
  787.    std::vector<std::string_view> SplitIntoWordsNoStop(std::string_view text) const;
  788.    
  789.    static int ComputeAverageRating(const std::vector<int>& ratings);
  790.  
  791.    struct QueryWord {
  792.        std::string_view data;
  793.        bool is_minus;
  794.        bool is_stop;
  795.    };
  796.  
  797.    QueryWord ParseQueryWord(std::string_view& text) const;
  798.  
  799.    struct Query {
  800.        std::vector<std::string_view> plus_words;
  801.        std::vector<std::string_view> minus_words;
  802.    };
  803.  
  804.    Query ParseQuery(std::string_view& text) const;
  805.        
  806.    double ComputeWordInverseDocumentFreq(std::string_view& word) const;
  807.  
  808.    template <typename DocumentPredicate>
  809.    std::vector<Document> FindAllDocuments(const Query& query,
  810.                                           DocumentPredicate document_predicate) const;
  811.    template <typename DocumentPredicate>
  812.    std::vector<Document> FindAllDocuments(const std::execution::sequenced_policy&,
  813.                                           const Query& query,
  814.                                           DocumentPredicate document_predicate) const;
  815.    template <typename DocumentPredicate>
  816.    std::vector<Document> FindAllDocuments(const std::execution::parallel_policy&,
  817.                                           const Query& query,
  818.                                           DocumentPredicate document_predicate) const;
  819. };
  820.  
  821. template <typename StringContainer>
  822. SearchServer::SearchServer(const StringContainer& stop_words) : stop_words_(MakeUniqueNonEmptyStrings(stop_words)){
  823.    if (!all_of(stop_words_.begin(), stop_words_.end(), IsValidWord)) {
  824.        throw std::invalid_argument("Some of stop words are invalid"s);
  825.    }
  826. }
  827.  
  828. template <typename DocumentPredicate>
  829. std::vector<Document> SearchServer::FindTopDocuments(std::string_view raw_query,
  830.                                                     DocumentPredicate document_predicate) const {
  831.    return FindTopDocuments(std::execution::seq,
  832.                            raw_query,
  833.                            document_predicate);
  834. }
  835.  
  836. template <typename DocumentPredicate>
  837. std::vector<Document> SearchServer::FindTopDocuments(const std::execution::sequenced_policy&,
  838.                                                     std::string_view raw_query,
  839.                                                     DocumentPredicate document_predicate) const {
  840.    const auto query = ParseQuery(raw_query);
  841.    auto matched_documents = FindAllDocuments(std::execution::seq,
  842.                                              query,
  843.                                              document_predicate);
  844.    
  845.    sort(std::execution::seq,
  846.         matched_documents.begin(),
  847.         matched_documents.end(),
  848.         [this](const Document& lhs, const Document& rhs) {
  849.             if (std::abs(lhs.relevance - rhs.relevance) < EPSILON) {
  850.                 return lhs.rating > rhs.rating;
  851.             } else {
  852.                 return lhs.relevance > rhs.relevance;
  853.             }
  854.         });
  855.    
  856.    if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  857.        matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  858.    }
  859.    
  860.    return matched_documents;
  861. }
  862.  
  863. template <typename DocumentPredicate>
  864. std::vector<Document> SearchServer::FindTopDocuments(const std::execution::parallel_policy&,
  865.                                                     std::string_view raw_query,
  866.                                                     DocumentPredicate document_predicate) const {
  867.    const auto query = ParseQuery(raw_query);
  868.    auto matched_documents = FindAllDocuments(std::execution::par,
  869.                                              query,
  870.                                              document_predicate);
  871.    
  872.    sort(std::execution::par,
  873.         matched_documents.begin(),
  874.         matched_documents.end(),
  875.         [this](const Document& lhs, const Document& rhs) {
  876.             if (std::abs(lhs.relevance - rhs.relevance) < EPSILON) {
  877.                 return lhs.rating > rhs.rating;
  878.             } else {
  879.                 return lhs.relevance > rhs.relevance;
  880.             }
  881.         });
  882.    
  883.    if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  884.        matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  885.    }
  886.    
  887.    return matched_documents;
  888. }
  889.  
  890. template <typename DocumentPredicate>
  891. std::vector<Document> SearchServer::FindAllDocuments(const Query& query,
  892.                                                     DocumentPredicate document_predicate) const {
  893.    return FindAllDocuments(std::execution::seq,
  894.                            query,
  895.                            document_predicate);
  896. }
  897. template <typename DocumentPredicate>
  898. std::vector<Document> SearchServer::FindAllDocuments(const std::execution::sequenced_policy&,
  899.                                                     const Query& query,
  900.                                                     DocumentPredicate document_predicate) const {
  901.    std::map<int, double> document_to_relevance;
  902.    
  903.    for (std::string_view word : query.plus_words) {
  904.            if (word_to_document_freqs_.count(word) == 0) {
  905.                continue;
  906.            }
  907.            const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  908.            for (const auto [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  909.                const auto& document_data = documents_.at(document_id);
  910.                if (document_predicate(document_id,
  911.                                       document_data.status,
  912.                                       document_data.rating)) {
  913.                    document_to_relevance[document_id] += term_freq * inverse_document_freq;
  914.                }
  915.            }
  916.        }
  917.  
  918.        for (const auto word : query.minus_words) {
  919.            if (word_to_document_freqs_.count(word) == 0) {
  920.                continue;
  921.            }
  922.            for (const auto [document_id, _] : word_to_document_freqs_.at(word)) {
  923.                document_to_relevance.erase(document_id);
  924.            }
  925.        }
  926.  
  927.        std::vector<Document> matched_documents;
  928.        for (const auto [document_id, relevance] : document_to_relevance) {
  929.            matched_documents.push_back({document_id,
  930.                                         relevance,
  931.                                         documents_.at(document_id).rating});
  932.        }
  933.  
  934.        return matched_documents;
  935.    }
  936.  
  937. template <typename DocumentPredicate>
  938. std::vector<Document> SearchServer::FindAllDocuments(const std::execution::parallel_policy&,
  939.                                                     const Query& query,
  940.                                                     DocumentPredicate document_predicate) const {
  941.    const int BUCKET_COUNT = 101;
  942.    ConcurrentMap<int, double> document_to_relevance(BUCKET_COUNT);
  943.  
  944.    const auto plus_func = [this,
  945.                       &document_predicate,
  946.                       &document_to_relevance] (std::string_view word) {
  947.                           if (word_to_document_freqs_.count(word) == 0) {//
  948.                                return;
  949.                           }
  950.                           const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  951.                           for (const auto& [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  952.                               const auto& document_data = documents_.at(document_id);//
  953.                               if (document_predicate(document_id,
  954.                                                      document_data.status,
  955.                                                      document_data.rating)) {
  956.                                   document_to_relevance[document_id].ref_to_value += term_freq * inverse_document_freq;
  957.                                }
  958.                            }
  959.                        };
  960.  
  961.    for_each(std::execution::par,
  962.             query.plus_words.begin(),
  963.             query.plus_words.end(),
  964.             plus_func);
  965.  
  966.    const auto minus_erase_func = [&](std::string_view word) {
  967.        if (word_to_document_freqs_.count(word) == 0) {
  968.            return;
  969.        }
  970.        for (const auto& [document_id, _] : word_to_document_freqs_.at(word)) {
  971.            document_to_relevance.erase(document_id);
  972.        }
  973.    };
  974.  
  975.    for_each(std::execution::par,
  976.             query.minus_words.begin(),
  977.             query.minus_words.end(),
  978.             minus_erase_func);
  979.    
  980.    const auto& document_to_relevance_bom = document_to_relevance.BuildOrdinaryMap();
  981.    
  982.    std::vector<Document> matched_documents;
  983.    for (const auto& [document_id, relevance] : document_to_relevance_bom) {
  984.        matched_documents.push_back({document_id,
  985.                                     relevance,
  986.                                     documents_.at(document_id).rating });
  987.    }
  988.    
  989.    return matched_documents;
  990. }
  991. -----------------------------------------------------------------------
  992. string_processing.cpp
  993. -----------------------------------------------------------------------
  994. #include "string_processing.h"
  995.  
  996. std::vector<std::string_view> SplitIntoWords(std::string_view text) {
  997.    
  998.    std::string_view delimiter = " ";
  999.    std::vector<std::string_view> words;
  1000.  
  1001.    int64_t start_pos = text.find_first_not_of(delimiter);
  1002.    const int64_t end_pos = text.npos;
  1003.  
  1004.    while (start_pos != end_pos) {
  1005.        int64_t space = text.find(' ', start_pos);
  1006.        words.push_back(space == end_pos
  1007.                        ? text.substr(start_pos)
  1008.                        : text.substr(start_pos, space - start_pos));
  1009.        start_pos = text.find_first_not_of(delimiter, space);
  1010.    }
  1011.    
  1012.    return words;
  1013. }
  1014. -----------------------------------------------------------------------
  1015. string_processing.h
  1016. -----------------------------------------------------------------------
  1017. #pragma once
  1018. #include <set>
  1019. #include <vector>
  1020. #include <string>
  1021. #include <iostream>
  1022.  
  1023. std::vector<std::string_view> SplitIntoWords(const std::string_view text);
  1024.  
  1025. template <typename StringContainer>
  1026. std::set<std::string, std::less<>> MakeUniqueNonEmptyStrings(const StringContainer& strings) {
  1027.    std::set<std::string, std::less<>> non_empty_strings;
  1028.    std::string str_buf;
  1029.    for (auto& str : strings) {
  1030.        str_buf = str;
  1031.        if (!str_buf.empty()) {
  1032.            non_empty_strings.insert(str_buf);
  1033.        }
  1034.    }
  1035.    return non_empty_strings;
  1036. }
  1037. -----------------------------------------------------------------------
  1038. test_example_functions.cpp
  1039. -----------------------------------------------------------------------
  1040.  
  1041. empty
  1042.  
  1043. -----------------------------------------------------------------------
  1044. test_example_functions.h
  1045. -----------------------------------------------------------------------
  1046.  
  1047. empty
  1048.  
  1049. -----------------------------------------------------------------------
  1050. concurrent_map.h
  1051. -----------------------------------------------------------------------
  1052. #pragma once
  1053. #include <algorithm>
  1054. #include <cstdlib>
  1055. #include <future>
  1056. #include <map>
  1057. #include <numeric>
  1058. #include <random>
  1059. #include <string>
  1060. #include <vector>
  1061. #include <mutex>
  1062.  
  1063. #include "log_duration.h"
  1064. #include "test_framework.h"
  1065.  
  1066. using namespace std::string_literals;
  1067.  
  1068. template <typename Key, typename Value>
  1069. class ConcurrentMap {
  1070. private:
  1071.    struct Bucket {
  1072.        std::mutex mutex_;
  1073.        std::map<Key, Value> map_;
  1074.    };
  1075.    
  1076.    std::vector<Bucket> bucket_;
  1077.    
  1078. public:
  1079.    static_assert(std::is_integral_v<Key>, "ConcurrentMap supports only integer keys"s);
  1080.  
  1081.    struct Access {
  1082.        std::lock_guard<std::mutex> lock_guard_mutex;
  1083.        Value& ref_to_value;
  1084.  
  1085.        Access(const Key& key, Bucket& bucket) : lock_guard_mutex(bucket.mutex_)
  1086.                                               , ref_to_value(bucket.map_[key]) {}
  1087.    };
  1088.  
  1089.    explicit ConcurrentMap(size_t bucket_count) : bucket_(bucket_count) {}
  1090.  
  1091.    Access operator[](const Key& key) {
  1092.    
  1093.        auto& bucket = bucket_[uint64_t(key) %bucket_.size()];
  1094.        return {key,
  1095.                bucket};
  1096.    }
  1097.  
  1098.    std::map<Key, Value> BuildOrdinaryMap() {
  1099.    
  1100.        std::map<Key, Value> result;
  1101.        
  1102.        for (auto& [mutex_, map_] : bucket_) {
  1103.            std::lock_guard lock_guard_mutex(mutex_);
  1104.            result.insert(map_.begin(), map_.end());
  1105.        }
  1106.        
  1107.        return result;
  1108.    }
  1109.    
  1110.    void erase(const Key& key){    
  1111.      auto& bucket = bucket_[static_cast<uint64_t>(key) % bucket_.size()];
  1112.         std::lock_guard lock_guard_mutex(bucket.mutex_);
  1113.         bucket.map_.erase(key);
  1114.    }
  1115. };
Advertisement
Add Comment
Please, Sign In to add comment