shushus

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

Mar 6th, 2023 (edited)
481
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 31.32 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),
  137.                                                                       end_(end),
  138.                                                                       size_(distance(begin, end)){}
  139.    
  140.    IteratorRanges begin() const  {
  141.        return begin_;
  142.    }
  143.    
  144.    IteratorRanges end() const {
  145.        return end_;
  146.    }
  147.    
  148.    size_t size() const {
  149.        return size_;
  150.    }
  151.    
  152. private:
  153.    IteratorRanges begin_;
  154.    IteratorRanges end_;
  155.    size_t size_;
  156. };
  157.  
  158. std::ostream& operator<<(std::ostream& out, const Document& document) {
  159.    out << "{ document_id = "s << document.id
  160.        << ", relevance = "s << document.relevance
  161.        << ", rating = "s << document.rating << " }"s;
  162.    return out;
  163. }
  164.  
  165. template <typename To_Out>
  166. std::ostream& operator<<(std::ostream& out, const IteratorRange<To_Out>& sheet) {
  167.    auto helper = sheet.begin();
  168.    while(helper != sheet.end()) {
  169.        out<< *helper;
  170.        ++helper;
  171.    }
  172.    return out;
  173. }
  174.  
  175. template <typename Paginatorr>
  176. class Paginator {
  177. public :
  178.    Paginator(const Paginatorr& result_begin, const Paginatorr& result_end, size_t size_of_sheet) {
  179.    
  180.        auto full_size = distance(result_begin, result_end);
  181.        Paginatorr helper = result_begin;
  182.        
  183.        for (auto i = 0; i < full_size/size_of_sheet; ++i) {
  184.            sheets.push_back(IteratorRange<Paginatorr>(helper, helper+ size_of_sheet));
  185.            helper=helper+size_of_sheet;
  186.        }
  187.        
  188.        if (helper!= result_end) {
  189.            sheets.push_back(IteratorRange<Paginatorr>(helper, result_end));
  190.        }
  191.    }
  192.    
  193.    auto begin() const {
  194.        return sheets.begin();
  195.    }
  196.    
  197.    auto end() const {
  198.        return sheets.end();
  199.    }
  200.    
  201.    size_t size() {
  202.        return sheets.size();
  203.    }
  204.    
  205. private:
  206.    std::vector<IteratorRange<Paginatorr>> sheets;
  207. };
  208.  
  209. template <typename Container>
  210. auto Paginate(const Container& c, size_t page_size) {
  211.    return Paginator(begin(c),
  212.                     end(c),
  213.                     page_size);
  214. }
  215. -----------------------------------------------------------------------
  216. process_queries.cpp
  217. -----------------------------------------------------------------------
  218. #include <execution>
  219. #include <algorithm>
  220. #include <list>
  221.  
  222. #include "process_queries.h"
  223.  
  224. std::vector<std::vector<Document>> ProcessQueries(const SearchServer& search_server,
  225.                                                  const std::vector<std::string>& queries) {
  226.    std::vector<std::vector<Document>> helper(queries.size());
  227.    std::transform(std::execution::par,
  228.                   queries.begin(),
  229.                   queries.end(),
  230.                   helper.begin(),
  231.                   [&search_server](auto query){
  232.                        return search_server.FindTopDocuments(query);
  233.                   });
  234.    return helper;
  235. }
  236.  
  237. std::vector<Document> ProcessQueriesJoined(const SearchServer& search_server,
  238.                                           const std::vector<std::string>& queries) {
  239.    return std::transform_reduce(std::execution::par,
  240.                                 queries.begin(),
  241.                                 queries.end(),
  242.                                 std::vector<Document>{},
  243.                                 [](std::vector<Document> lhs, std::vector<Document> const& rhs){
  244.                                     lhs.insert(lhs.end(), rhs.begin(), rhs.end());
  245.                                     return lhs;
  246.                                 },            
  247.                                 [&search_server](auto query){
  248.                                     return search_server.FindTopDocuments(query);
  249.                                 });
  250. }
  251. -----------------------------------------------------------------------
  252. process_queries.h
  253. -----------------------------------------------------------------------
  254. #pragma once
  255. #include "search_server.h"
  256. #include <vector>
  257. #include <string>
  258.  
  259. std::vector<std::vector<Document>> ProcessQueries(const SearchServer& search_server,
  260.    const std::vector<std::string>& queries);
  261.  
  262. std::vector<Document> ProcessQueriesJoined(const SearchServer& search_server,
  263.    const std::vector<std::string>& queries);
  264. -----------------------------------------------------------------------
  265. read_input_functions.cpp
  266. -----------------------------------------------------------------------
  267. #include "read_input_functions.h"
  268. #include <iostream>
  269.  
  270. using namespace std::string_literals;
  271.  
  272. std::string ReadLine() {
  273.    std::string s;
  274.    std::getline(std::cin, s);
  275.    return s;
  276. }
  277.  
  278. int ReadLineWithNumber() {
  279.    int result;
  280.    std::cin >> result;
  281.    ReadLine();
  282.    return result;
  283. }
  284. -----------------------------------------------------------------------
  285. read_input_functions.h
  286. -----------------------------------------------------------------------
  287. #pragma once
  288. #include "document.h"
  289. #include <string>
  290.  
  291. std::string ReadLine();
  292. int ReadLineWithNumber();
  293. -----------------------------------------------------------------------
  294. request_queue.cpp
  295. -----------------------------------------------------------------------
  296. #include "request_queue.h"
  297.  
  298. std::vector<Document> RequestQueue::AddFindRequest(std::string_view raw_query,
  299.                                                   DocumentStatus status) {
  300.    return AddFindRequest(raw_query,
  301.                          [&status](int document_id,
  302.                                    DocumentStatus document_status,
  303.                                    int rating) {
  304.                                        return document_status == status;
  305.                                    });
  306. }
  307.    
  308. std::vector<Document> RequestQueue::AddFindRequest(std::string_view raw_query) {
  309.    
  310.    return AddFindRequest(raw_query,
  311.                          DocumentStatus::ACTUAL);
  312. }
  313.    
  314. int RequestQueue::GetNoResultRequests() const {
  315.    return count_if(requests_.begin(),
  316.                    requests_.end(),
  317.                    [](QueryResult query) {
  318.                        return query.query_result == 0;
  319.                    });
  320. }
  321. -----------------------------------------------------------------------
  322. request_queue.h
  323. -----------------------------------------------------------------------
  324. #pragma once
  325. #include "search_server.h"
  326. #include <deque>
  327.  
  328. class RequestQueue {
  329. public:
  330.    RequestQueue(const SearchServer& search_server) : search_request(search_server){}
  331.    
  332.    template <typename DocumentPredicate>
  333.    std::vector<Document> AddFindRequest(std::string_view raw_query, DocumentPredicate document_predicate);
  334.    std::vector<Document> AddFindRequest(std::string_view raw_query, DocumentStatus status);
  335.    std::vector<Document> AddFindRequest(std::string_view raw_query);
  336.    
  337.    int GetNoResultRequests() const;
  338. private:
  339.    struct QueryResult {
  340.        bool query_result;
  341.    };
  342.    
  343.    const SearchServer& search_request;
  344.    std::deque<QueryResult> requests_;
  345.    const static int min_in_day_ = 1440;
  346. };
  347.  
  348. template <typename DocumentPredicate>
  349. std::vector<Document> RequestQueue::AddFindRequest(std::string_view raw_query,
  350.                                                   DocumentPredicate document_predicate) {
  351.    std::vector<Document> helper = search_request.FindTopDocuments(raw_query,
  352.                                                                   document_predicate);
  353.    QueryResult query;
  354.    query.query_result = (helper.empty()==false);
  355.    
  356.    if (!(requests_.size() < min_in_day_)){
  357.        requests_.pop_front();
  358.    }
  359.    
  360.    requests_.push_back(query);
  361.    return helper;
  362. }
  363. -----------------------------------------------------------------------
  364. search_server.cpp
  365. -----------------------------------------------------------------------
  366. #include <numeric>
  367. #include "search_server.h"
  368.  
  369. void SearchServer::AddDocument(int document_id,
  370.                               std::string_view document,
  371.                               DocumentStatus status,
  372.                               const std::vector<int>& ratings) {
  373.    
  374.    if ((document_id < 0) || (documents_.count(document_id) > 0)) {
  375.        throw std::invalid_argument("Invalid document ID"s);
  376.    }
  377.    
  378.    auto [doc_id_, doc_data_] = documents_.emplace(document_id,
  379.                                                   DocumentData{
  380.                                                       std::string(document),
  381.                                                       ComputeAverageRating(ratings),
  382.                                                       status
  383.                                                    });
  384.    document_ids_.push_back(document_id);
  385.    
  386.    const auto words = SplitIntoWordsNoStop(doc_id_->second.data_string_);
  387.    
  388.    const double inv_word_count = 1.0 / words.size();
  389.    
  390.    for (auto word : words) {
  391.        word_to_document_freqs_[word][document_id] += inv_word_count;
  392.        ids_of_docs_to_word_freqs_[document_id][word] += inv_word_count;
  393.    }
  394. }
  395.  
  396. std::vector<Document> SearchServer::FindTopDocuments(std::string_view raw_query,
  397.                                                     DocumentStatus status) const {
  398.    return FindTopDocuments(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(std::string_view raw_query) const {
  408.    return FindTopDocuments(raw_query,
  409.                            DocumentStatus::ACTUAL);
  410. }
  411.  
  412. int SearchServer::GetDocumentCount() const {
  413.    return documents_.size();
  414. }
  415.  
  416. std::vector<int>::const_iterator SearchServer::begin() const {
  417.    return document_ids_.begin();
  418. }
  419.  
  420. std::vector<int>::const_iterator SearchServer::end() const {
  421.    return document_ids_.end();
  422. }
  423.  
  424. const std::map<std::string_view, double>& SearchServer::GetWordFrequencies(int document_id) const {
  425.    static const std::map<std::string_view, double> emptyes;
  426.    return (!ids_of_docs_to_word_freqs_.count(document_id))
  427.            ? emptyes
  428.            : ids_of_docs_to_word_freqs_.at(document_id);
  429. }
  430.  
  431. void SearchServer::RemoveDocument(int document_id) {
  432.    RemoveDocument(std::execution::seq,
  433.                   document_id);
  434. }
  435.  
  436. void SearchServer::RemoveDocument(const std::execution::sequenced_policy&,
  437.                                  int document_id) {
  438.    auto helper = std::find(
  439.                            document_ids_.begin(),
  440.                            document_ids_.end(),
  441.                            document_id);
  442.    
  443.    if (helper == document_ids_.end()) {
  444.        return;
  445.    } else {
  446.        document_ids_.erase(helper);
  447.    }
  448.        
  449.    documents_.erase(document_id);
  450.    
  451.    std::for_each(word_to_document_freqs_.begin(),
  452.                  word_to_document_freqs_.end(),
  453.                  [&](auto& helper) {
  454.                      helper.second.erase(document_id);
  455.                  });
  456. }
  457.  
  458. void SearchServer::RemoveDocument(const std::execution::parallel_policy&,
  459.                                  int document_id) {
  460.    auto helper = std::find(std::execution::par,
  461.                            document_ids_.begin(),
  462.                            document_ids_.end(),
  463.                            document_id);
  464.    
  465.    if (helper == document_ids_.end()) {
  466.        return;
  467.    } else {
  468.        document_ids_.erase(helper);
  469.    }
  470.  
  471.    documents_.erase(document_id);
  472.    
  473.    std::for_each(std::execution::par,
  474.        word_to_document_freqs_.begin(),
  475.                   word_to_document_freqs_.end(),
  476.                   [&](auto& helper) {
  477.                       helper.second.erase(document_id);
  478.                   });
  479. }
  480.  
  481. std::tuple<std::vector<std::string_view>, DocumentStatus> SearchServer::MatchDocument(std::string_view raw_query,
  482.                                                                                      int document_id) const {
  483.    return MatchDocument(std::execution::seq,
  484.                         raw_query,
  485.                         document_id);
  486. }
  487.  
  488. std::tuple<std::vector<std::string_view>, DocumentStatus> SearchServer::MatchDocument(const std::execution::sequenced_policy&,
  489.                                                                                      std::string_view raw_query,
  490.                                                                                      int document_id) const {
  491.  
  492.    if ((document_id < 0) || (documents_.count(document_id) <= 0)) {
  493.        throw std::invalid_argument("Non-existent document ID"s);
  494.    }
  495.    
  496.    const auto result = ParseQuery(raw_query, std::execution::seq);
  497.    std::vector<std::string_view> matched_words;
  498.    
  499.    for (auto word : result.minus_words) {
  500.        if (word_to_document_freqs_.count(word) == 0) {
  501.            continue;
  502.        }
  503.        if (word_to_document_freqs_.at(word).count(document_id)) {
  504.            return {{}, documents_.at(document_id).status};
  505.        }
  506.    }
  507.    
  508.    for (auto word : result.plus_words) {
  509.        if (word_to_document_freqs_.count(word) == 0) {
  510.            continue;
  511.        }
  512.        if (word_to_document_freqs_.at(word).count(document_id)) {
  513.            matched_words.push_back(word);
  514.        }
  515.    }
  516.  
  517.    return {matched_words,
  518.            documents_.at(document_id).status};
  519. }
  520.  
  521. std::tuple<std::vector<std::string_view>, DocumentStatus> SearchServer::MatchDocument(const std::execution::parallel_policy&,
  522.                                                                                      std::string_view raw_query,
  523.                                                                                      int document_id) const {
  524.    
  525.    if ((document_id < 0) || (documents_.count(document_id) <= 0)) {
  526.        throw std::invalid_argument("Non-existent document ID"s);
  527.    }
  528.    
  529.    const auto& result = ParseQuery(raw_query);    
  530.  
  531.    const auto& checker = [this, document_id](std::string_view word) {
  532.        const auto helper = word_to_document_freqs_.find(word);
  533.        return helper!= word_to_document_freqs_.end() &&
  534.                        helper->second.count(document_id);        
  535.    };
  536.  
  537.    if (std::any_of(std::execution::par,
  538.                    result.minus_words.begin(),
  539.                    result.minus_words.end(),
  540.                    checker)) {
  541.        return {{}, documents_.at(document_id).status};
  542.    }
  543.    
  544.    std::vector<std::string_view> matched_words(result.plus_words.size());
  545.    
  546.    auto end = std::copy_if(std::execution::par,
  547.                            result.plus_words.begin(),
  548.                            result.plus_words.end(),
  549.                            matched_words.begin(),
  550.                            checker);
  551.    
  552.    std::sort(matched_words.begin(), end);
  553.    end = std::unique(std::execution::par,
  554.                      matched_words.begin(),
  555.                      end);
  556.    
  557.    matched_words.erase(end, matched_words.end());
  558.    return {matched_words,
  559.            documents_.at(document_id).status};
  560. }
  561.  
  562. bool SearchServer::IsStopWord(std::string_view word) const {
  563.    return stop_words_.count(word) > 0;
  564. }
  565.  
  566. bool SearchServer::IsValidWord(std::string_view word) {
  567.    return std::none_of(word.begin(),
  568.                        word.end(),
  569.                        [](char c) {
  570.                            return c >= '\0' && c < ' ';
  571.                        }
  572.    );
  573. }
  574.  
  575. std::vector<std::string_view> SearchServer::SplitIntoWordsNoStop(std::string_view text) const {
  576.    std::vector<std::string_view> words;
  577.    
  578.    for (std::string_view& word : SplitIntoWords(text)) {        
  579.        if (!IsValidWord(word)) {
  580.            throw std::invalid_argument("Word "s + std::string(word) + " is invalid"s);
  581.        }
  582.        if (!IsStopWord(word)) {
  583.            words.push_back(word);
  584.        }
  585.    }
  586.    return words;
  587. }
  588.  
  589. int SearchServer::ComputeAverageRating(const std::vector<int>& ratings) {
  590.    if (ratings.empty()) {
  591.        return 0;
  592.    }
  593.    int rating_sum = std::accumulate(ratings.begin(),
  594.                                     ratings.end(),
  595.                                     0);
  596.    return rating_sum /static_cast<int>(ratings.size());
  597. }
  598.  
  599. SearchServer::QueryWord SearchServer::ParseQueryWord(std::string_view& text) const {
  600.    if (text.empty()) {
  601.        throw std::invalid_argument("Query word is empty"s);
  602.    }
  603.    
  604.    bool is_minus = false;
  605.    
  606.    if (text[0] == '-') {
  607.        is_minus = true;
  608.        text = text.substr(1);
  609.    }
  610.    
  611.    if (text.empty() || text[0] == '-' || !IsValidWord(text)) {
  612.        throw std::invalid_argument("Query word "s + std::string(text) + " is invalid");
  613.    }
  614.    return {text, is_minus, IsStopWord(text)};
  615. }
  616.  
  617. SearchServer::Query SearchServer::ParseQuery(std::string_view& text) const {
  618.    Query result;
  619.    for (std::string_view& word : SplitIntoWords(text)) {
  620.        const auto query_word = ParseQueryWord(word);
  621.        if (!query_word.is_stop) {
  622.            if (query_word.is_minus) {
  623.                result.minus_words.push_back(query_word.data);
  624.            } else {
  625.                result.plus_words.push_back(query_word.data);
  626.            }
  627.        }
  628.    }
  629.    return result;
  630. }
  631.  
  632. SearchServer::Query SearchServer::ParseQuery(std::string_view& text, const std::execution::sequenced_policy&) const {
  633.    Query result;
  634.    result = ParseQuery(text);
  635.  
  636.    std::sort(std::execution::par,
  637.              result.minus_words.begin(),
  638.              result.minus_words.end());
  639.    std::sort(std::execution::par,
  640.              result.plus_words.begin(),
  641.              result.plus_words.end());
  642.  
  643.    result.minus_words.erase(std::unique(result.minus_words.begin(),
  644.                                         result.minus_words.end()),
  645.                             result.minus_words.end());
  646.    result.plus_words.erase(std::unique(result.plus_words.begin(),
  647.                                        result.plus_words.end()),
  648.                            result.plus_words.end());
  649.  
  650.    return result;
  651. }
  652.  
  653. double SearchServer::ComputeWordInverseDocumentFreq(std::string_view& word) const {
  654.    return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  655. }
  656. -----------------------------------------------------------------------
  657. search_server.h
  658. -----------------------------------------------------------------------
  659. #pragma once
  660. #include <tuple>
  661. #include <algorithm>
  662. #include <cmath>
  663. #include <iostream>
  664. #include <map>
  665. #include <set>
  666. #include <stdexcept>
  667. #include <execution>
  668. #include <string>
  669. #include <vector>
  670. #include "read_input_functions.h"
  671. #include "string_processing.h"
  672. #include "log_duration.h"
  673.  
  674. using namespace std::string_literals;
  675.  
  676. class SearchServer {
  677. public:
  678.    template <typename StringContainer>
  679.    SearchServer(const StringContainer& stop_words);
  680.    SearchServer(const std::string& stop_words_text) : SearchServer(SplitIntoWords(stop_words_text)){}
  681.    SearchServer(std::string_view& stop_words_text) : SearchServer(SplitIntoWords(stop_words_text)){}
  682.    SearchServer() = default;
  683.    
  684.    void AddDocument(int document_id,
  685.                     std::string_view document,
  686.                     DocumentStatus status,
  687.                     const std::vector<int>& ratings);
  688.    
  689.    template <typename DocumentPredicate>
  690.    std::vector<Document> FindTopDocuments(std::string_view raw_query,
  691.                                           DocumentPredicate document_predicate) const;
  692.    std::vector<Document> FindTopDocuments(std::string_view raw_query,
  693.                                           DocumentStatus status) const;
  694.    std::vector<Document> FindTopDocuments(std::string_view raw_query) const;
  695.    
  696.    int GetDocumentCount() const;
  697.    
  698.    std::vector<int>::const_iterator begin() const;
  699.    std::vector<int>::const_iterator end() const;
  700.    
  701.    const std::map<std::string_view, double>& GetWordFrequencies(int document_id) const;
  702.    
  703.    void RemoveDocument(int document_id);
  704.    void RemoveDocument(const std::execution::sequenced_policy&,
  705.                        int document_id);
  706.    void RemoveDocument(const std::execution::parallel_policy&,
  707.                        int document_id);
  708.    
  709.    std::tuple<std::vector<std::string_view>, DocumentStatus> MatchDocument(std::string_view raw_query,
  710.                                                                       int document_id) const;
  711.    std::tuple<std::vector<std::string_view>, DocumentStatus> MatchDocument(const std::execution::sequenced_policy&,
  712.                                                                       std::string_view raw_query,
  713.                                                                       int document_id) const;
  714.    std::tuple<std::vector<std::string_view>, DocumentStatus> MatchDocument(const std::execution::parallel_policy&,
  715.                                                                       std::string_view raw_query,
  716.                                                                       int document_id) const;    
  717.  
  718. private:
  719.    struct DocumentData {
  720.        std::string data_string_;
  721.        int rating;
  722.        DocumentStatus status;
  723.    };
  724.    
  725.    const double EPSILON = 1e-6;
  726.    const int MAX_RESULT_DOCUMENT_COUNT = 5;
  727.    
  728.    const std::set<std::string, std::less<>> stop_words_;
  729.    
  730.    std::map<std::string_view, std::map<int, double>> word_to_document_freqs_;
  731.    std::map<int, std::map<std::string_view, double>> ids_of_docs_to_word_freqs_;
  732.    
  733.    std::map<int, DocumentData> documents_;
  734.    std::vector<int> document_ids_;
  735.  
  736.    bool IsStopWord(std::string_view word) const;
  737.    static bool IsValidWord(std::string_view word);
  738.    
  739.    std::vector<std::string_view> SplitIntoWordsNoStop(std::string_view text) const;
  740.    
  741.    static int ComputeAverageRating(const std::vector<int>& ratings);
  742.  
  743.    struct QueryWord {
  744.        std::string_view data;
  745.        bool is_minus;
  746.        bool is_stop;
  747.    };
  748.  
  749.    QueryWord ParseQueryWord(std::string_view& text) const;
  750.  
  751.    struct Query {
  752.        std::vector<std::string_view> plus_words;
  753.        std::vector<std::string_view> minus_words;
  754.    };
  755.  
  756.    Query ParseQuery(std::string_view& text) const;
  757.    Query ParseQuery(std::string_view& text, const std::execution::sequenced_policy&) const;
  758.        
  759.    double ComputeWordInverseDocumentFreq(std::string_view& word) const;
  760.  
  761.    template <typename DocumentPredicate>
  762.    std::vector<Document> FindAllDocuments(const Query& query,
  763.                                           DocumentPredicate document_predicate) const;
  764. };
  765.  
  766. template <typename StringContainer>
  767. SearchServer::SearchServer(const StringContainer& stop_words) : stop_words_(MakeUniqueNonEmptyStrings(stop_words)){
  768.    if (!all_of(stop_words_.begin(), stop_words_.end(), IsValidWord)) {
  769.        throw std::invalid_argument("Some of stop words are invalid"s);
  770.    }
  771. }
  772.  
  773. template <typename DocumentPredicate>
  774. std::vector<Document> SearchServer::FindTopDocuments(std::string_view raw_query,
  775.                                                     DocumentPredicate document_predicate) const {
  776.    const auto query = ParseQuery(raw_query, std::execution::seq);
  777.    auto matched_documents = FindAllDocuments(query,
  778.                                              document_predicate);
  779.    
  780.    sort(std::execution::par,
  781.         matched_documents.begin(),
  782.         matched_documents.end(),
  783.         [this](const Document& lhs, const Document& rhs) {
  784.             if (std::abs(lhs.relevance - rhs.relevance) < EPSILON) {
  785.                 return lhs.rating > rhs.rating;
  786.             } else {
  787.                 return lhs.relevance > rhs.relevance;
  788.             }
  789.         });
  790.    
  791.    if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  792.        matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  793.    }
  794.    
  795.    return matched_documents;
  796. }
  797.  
  798. template <typename DocumentPredicate>
  799. std::vector<Document> SearchServer::FindAllDocuments(const Query& query,
  800.                                                     DocumentPredicate document_predicate) const {
  801.    std::map<int, double> document_to_relevance;
  802.    
  803.    for (auto word : query.plus_words) {
  804.        if (word_to_document_freqs_.count(word) == 0) {
  805.            continue;
  806.        }
  807.        
  808.        const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  809.        
  810.        for (const auto [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  811.            const auto& document_data = documents_.at(document_id);
  812.            
  813.            if (document_predicate(document_id, document_data.status, document_data.rating)) {
  814.                document_to_relevance[document_id] += term_freq * inverse_document_freq;
  815.            }
  816.        }
  817.    }
  818.  
  819.    for (auto word : query.minus_words) {
  820.        if (word_to_document_freqs_.count(word) == 0) {
  821.            continue;
  822.        }
  823.        for (const auto [document_id, _] : word_to_document_freqs_.at(word)) {
  824.            document_to_relevance.erase(document_id);
  825.        }
  826.    }
  827.  
  828.    std::vector<Document> matched_documents;
  829.    
  830.    for (const auto [document_id, relevance] : document_to_relevance) {
  831.        matched_documents.push_back({document_id,
  832.                                     relevance,
  833.                                     documents_.at(document_id).rating
  834.                                    });
  835.    }
  836.    
  837.    return matched_documents;
  838. }
  839. -----------------------------------------------------------------------
  840. string_processing.cpp
  841. -----------------------------------------------------------------------
  842. #include "string_processing.h"
  843.  
  844. std::vector<std::string_view> SplitIntoWords(std::string_view text) {
  845.    
  846.    std::string_view delimiter = " ";
  847.    std::vector<std::string_view> words;
  848.  
  849.    int64_t start_pos = text.find_first_not_of(delimiter);
  850.    const int64_t end_pos = text.npos;
  851.  
  852.    while (start_pos != end_pos) {
  853.        int64_t space = text.find(' ', start_pos);
  854.        words.push_back(space == end_pos
  855.                        ? text.substr(start_pos)
  856.                        : text.substr(start_pos, space - start_pos));
  857.        start_pos = text.find_first_not_of(delimiter, space);
  858.    }
  859.    
  860.    return words;
  861. }
  862. -----------------------------------------------------------------------
  863. string_processing.h
  864. -----------------------------------------------------------------------
  865. #pragma once
  866. #include <set>
  867. #include <vector>
  868. #include <string>
  869. #include <iostream>
  870.  
  871. std::vector<std::string_view> SplitIntoWords(const std::string_view text);
  872.  
  873. template <typename StringContainer>
  874. std::set<std::string, std::less<>> MakeUniqueNonEmptyStrings(const StringContainer& strings) {
  875.    std::set<std::string, std::less<>> non_empty_strings;
  876.    std::string str_buf;
  877.    for (auto& str : strings) {
  878.        str_buf = str;
  879.        if (!str_buf.empty()) {
  880.            non_empty_strings.insert(str_buf);
  881.        }
  882.    }
  883.    return non_empty_strings;
  884. }
  885. -----------------------------------------------------------------------
  886. test_example_functions.cpp
  887. -----------------------------------------------------------------------
  888.  
  889. empty
  890.  
  891. -----------------------------------------------------------------------
  892. test_example_functions.h
  893. -----------------------------------------------------------------------
  894.  
  895. empty
  896.  
Advertisement
Add Comment
Please, Sign In to add comment