Esempio n. 1
0
    def get(self, query: Query) -> Optional[SearchResultPage]:
        """Get a cached page of search results for the query.

        The cached next page will only be returned if it matches the query_str,
        page_num, and user_id of the query.

        Args:
            query: Query to get the cached next page of search results for.

        Returns:
            The cached page of search results matching the given query, or None
            if a page of search results matching the query is not in the next
            page cache.
        """
        cache_key = self._get_query_page_cache_key(query)
        if cache_key is None:
            return None

        cached_results = self._redis_client.hget(cache_key, 'search_results')
        page = SearchResultPage(query=query)
        serialize.deserialize_search_results(cached_results, page)
        for result in page.search_results:
            article_id = result.article.database_id
            cached_article = self._redis_client.hget(cache_key,
                                                     str(article_id))
            serialize.deserialize_article(cached_article, result.article)

        return page
Esempio n. 2
0
    def update(
            self, query: Query,
            updated_article_keys: List[ArticleRankKey]) -> CacheUpdateResult:
        """Update the cached first page of search results for the given query.

        First, checks to see if any of the articles referenced by the given
        updated article rank keys are in the first page of search results
        currently cached for the query. Then, does one of the following:
            - If none of the referenced articles are in the cached page,
              returns UNNECESSARY and takes no other action.
            - If some or all of the referenced articles are in the cached page
              and all of the referenced articles will still be in the cached
              page after the update, rearranges the article order of the page
              in the cache and returns SUCCESSFUL.
            - If some or all of the referenced articles are in the cached page,
              but not all of the referenced articles will still be in the
              cached page after the update, returns RECACHE_REQUIRED and takes
              no other action.

        Args:
            query: Query to update the cached first page of search results for.
            updated_article_keys: The updated article rank keys for the
                articles for the query that should be updated in the cache.

        Returns:
            The result of the cache update.
        """
        cached_results = self._redis_client.get(f'query:{query.query_str}')
        if cached_results is None:
            return CacheUpdateResult.RECACHE_REQUIRED

        updated_article_found = False
        page = SearchResultPage(query=query)
        serialize.deserialize_search_results(cached_results, page)
        updated_article_id_map = {
            k.database_id: k
            for k in updated_article_keys
        }
        for result in page.search_results:
            if result.article.database_id not in updated_article_id_map:
                continue

            # Check if article is still on first page after update
            rank_key = updated_article_id_map[result.article.database_id]
            lowest_rank_key = page.search_results[-1].get_rank_key()
            if (page.total_results > SEARCH_RESULTS_PAGE_SIZE
                    and rank_key < lowest_rank_key):
                return CacheUpdateResult.RECACHE_REQUIRED

            result.quality_score = rank_key.quality_score
            updated_article_found = True

        if not updated_article_found:
            return CacheUpdateResult.UNNECESSARY

        # Reorder search results using the updated article scores
        page.search_results.sort(key=lambda r: r.get_rank_key(), reverse=True)
        serialized_results = serialize.serialize_search_results(page)
        self._redis_client.set(f'query:{query.query_str}', serialized_results)
        return CacheUpdateResult.SUCCESSFUL
Esempio n. 3
0
    def is_recache_required(self, query: Query,
                            new_article_key: ArticleRankKey) -> bool:
        """Check if a recache is required to add a new article for the query.

        Args:
            query: Query whose cache entry to check to see if a recache is
                required to add the article referenced by the given article
                key.
            new_article_key: The article rank key for a new article to check if
                should be included in the cache entry for the given query.

        Returns:
            True if a recache is required to add the article referened by the
            given article rank key to the entry for the given query, and False
            if a recache is not required.
        """
        cached_results = self._redis_client.get(f'query:{query.query_str}')
        if cached_results is None:
            return True

        page = SearchResultPage(query=query)
        serialize.deserialize_search_results(cached_results, page)
        if page.total_results < SEARCH_RESULTS_PAGE_SIZE:
            return True

        return new_article_key > page.search_results[-1].get_rank_key()
Esempio n. 4
0
    def get(self, query: Query) -> Optional[SearchResultPage]:
        """Get the cached first page of search results for the given query.

        Args:
            query: Query to get the cached first page of search results for.

        Returns:
            The cached first page of search results for the query, or None if
            the first page of search results is not in the cache for the query.
        """
        cached_results = self._redis_client.get(f'query:{query.query_str}')
        if cached_results is None:
            return None

        page = SearchResultPage(query=query)
        serialize.deserialize_search_results(cached_results, page)
        for result in page.search_results:
            article_id = result.article.database_id
            cached_article = self._redis_client.get(f'article:{article_id}')
            if cached_article is None:
                utils.log_and_raise(
                    _log, DataAccessError,
                    f'Article key for ID "{article_id}" not found in first '
                    f'cache')
            serialize.deserialize_article(cached_article, result.article)

        return page
Esempio n. 5
0
    def increment_total_result_count(self, query: Query,
                                     increment_amount: int) -> None:
        """Increment the total result count cached for the given query.

        Does nothing if the given query does not currently have an entry in the
        cache.

        Args:
            query: Query whose cached total result count to increment.
            increment_amount: Amount to increment the total result by.
        """
        cached_results = self._redis_client.get(f'query:{query.query_str}')
        if cached_results is None:
            return

        page = SearchResultPage(query=query)
        serialize.deserialize_search_results(cached_results, page)
        page.total_results += increment_amount
        serialized_results = serialize.serialize_search_results(page)
        self._redis_client.set(f'query:{query.query_str}', serialized_results)