def test_classic_query_id_list(self, mock_Elasticsearch, mock_Search): """:class:`.index.search` supports :class:`SimpleQuery`.""" mock_results = mock.MagicMock() mock_results.__getitem__.return_value = {"total": 53} rdata = mock_rdata() mock_result = mock.MagicMock(_d_=rdata, **rdata) mock_result.meta.score = 1 mock_results.__iter__.return_value = [mock_result] mock_Search.execute.return_value = mock_results # Support the chaining API for py-ES. mock_Search.return_value = mock_Search mock_Search.filter.return_value = mock_Search mock_Search.highlight.return_value = mock_Search mock_Search.highlight_options.return_value = mock_Search mock_Search.query.return_value = mock_Search mock_Search.sort.return_value = mock_Search mock_Search.__getitem__.return_value = mock_Search query = ClassicAPIQuery( id_list=["1234.56789"], order=SortOrder(by=SortBy.relevance), size=10, ) document_set = index.SearchSession.search(query) # self.assertIsInstance(document_set, DocumentSet) self.assertEqual(document_set["metadata"]["start"], 0) self.assertEqual(document_set["metadata"]["total_results"], 53) self.assertEqual(document_set["metadata"]["current_page"], 1) self.assertEqual(document_set["metadata"]["total_pages"], 6) self.assertEqual(document_set["metadata"]["size"], 10) self.assertEqual(len(document_set["results"]), 1)
def test_to_query_string(self): """Test classic API query string creation.""" self.assertEqual( ClassicAPIQuery(id_list=[]).to_query_string(), "search_query=&id_list=&start=0&max_results=10", ) self.assertEqual( ClassicAPIQuery(search_query="all:electron", id_list=[]).to_query_string(), "search_query=all:electron&id_list=&start=0&max_results=10", ) self.assertEqual( ClassicAPIQuery( search_query="all:electron", id_list=["1705.09169v3", "1705.09129v3"], ).to_query_string(), "search_query=all:electron&id_list=1705.09169v3,1705.09129v3" "&start=0&max_results=10", ) self.assertEqual( ClassicAPIQuery( search_query="all:electron", id_list=["1705.09169v3", "1705.09129v3"], page_start=3, ).to_query_string(), "search_query=all:electron&id_list=1705.09169v3,1705.09129v3" "&start=3&max_results=10", ) self.assertEqual( ClassicAPIQuery( search_query="all:electron", id_list=["1705.09169v3", "1705.09129v3"], page_start=3, size=50, ).to_query_string(), "search_query=all:electron&id_list=1705.09169v3,1705.09129v3" "&start=3&max_results=50", ) self.assertEqual( ClassicAPIQuery(search_query="all:electron", page_start=3, size=50).to_query_string(), "search_query=all:electron&id_list=&start=3&max_results=50", ) self.assertEqual( ClassicAPIQuery(id_list=["1705.09169v3", "1705.09129v3"], page_start=3, size=50).to_query_string(), "search_query=&id_list=1705.09169v3,1705.09129v3" "&start=3&max_results=50", ) self.assertEqual( ClassicAPIQuery(search_query="all:electron", size=50).to_query_string(), "search_query=all:electron&id_list=&start=0&max_results=50", )
def test_classic_query_complex(self, mock_Elasticsearch, mock_Search): """:class:`.index.search` supports :class:`SimpleQuery`.""" mock_results = mock.MagicMock() mock_results.__getitem__.return_value = {"total": 53} rdata = mock_rdata() mock_result = mock.MagicMock(_d_=rdata, **rdata) mock_result.meta.score = 1 mock_results.__iter__.return_value = [mock_result] mock_Search.execute.return_value = mock_results # Support the chaining API for py-ES. mock_Search.return_value = mock_Search mock_Search.filter.return_value = mock_Search mock_Search.highlight.return_value = mock_Search mock_Search.highlight_options.return_value = mock_Search mock_Search.query.return_value = mock_Search mock_Search.sort.return_value = mock_Search mock_Search.__getitem__.return_value = mock_Search query = ClassicAPIQuery( phrase=( Operator.OR, Term(Field.Author, "copernicus"), (Operator.ANDNOT, Term(Field.Title, "dark matter")), ), order=SortOrder(by=SortBy.relevance), size=10, ) document_set = index.SearchSession.search(query) # self.assertIsInstance(document_set, DocumentSet) self.assertEqual(document_set["metadata"]["start"], 0) self.assertEqual(document_set["metadata"]["total_results"], 53) self.assertEqual(document_set["metadata"]["current_page"], 1) self.assertEqual(document_set["metadata"]["total_pages"], 6) self.assertEqual(document_set["metadata"]["size"], 10) self.assertEqual(len(document_set["results"]), 1)
def test_classis_query_creation(self): self.assertRaises(ValueError, lambda: ClassicAPIQuery()) # There is no assert not raises self.assertIsNotNone(ClassicAPIQuery(search_query="")) self.assertIsNotNone(ClassicAPIQuery(id_list=[]))
def query( params: MultiDict, ) -> Tuple[ClassicSearchResponseData, HTTPStatus, Dict[str, Any]]: """ Handle a search request from the Clasic API. First, the method maps old request parameters to new parameters: - search_query -> query - start -> start - max_results -> size Then the request is passed to :method:`search()` and returned. If ``id_list`` is specified in the parameters and ``search_query`` is NOT specified, then each request is passed to :method:`paper()` and results are aggregated. If ``id_list`` is specified AND ``search_query`` is also specified, then the results from :method:`search()` are filtered by ``id_list``. Parameters ---------- params : :class:`MultiDict` GET query parameters from the request. Returns ------- SearchResponseData Response data (to serialize). int HTTP status code. dict Extra headers for the response. Raises ------ :class:`BadRequest` Raised when the search_query and id_list are not specified. """ params = params.copy() # Parse classic search query. search_query = params.get("search_query", None) # Parse id_list. id_list = params.get("id_list", "") if id_list: id_list = id_list.split(",") # Check arxiv id validity for arxiv_id in id_list: try: parse_arxiv_id(arxiv_id) except ValueError: raise ValidationError( message="incorrect id format for {}".format(arxiv_id), link=( "http://arxiv.org/api/errors#" "incorrect_id_format_for_{}" ).format(arxiv_id), ) else: id_list = None # Parse result size. try: max_results = int(params.get("max_results", 10)) except ValueError: raise ValidationError( message="max_results must be an integer", link="http://arxiv.org/api/errors#max_results_must_be_an_integer", ) if max_results < 0: raise ValidationError( message="max_results must be non-negative", link="http://arxiv.org/api/errors#max_results_must_be_" "non-negative", ) # Parse result start point. try: start = int(params.get("start", 0)) except ValueError: raise ValidationError( message="start must be an integer", link="http://arxiv.org/api/errors#start_must_be_an_integer", ) if start < 0: raise ValidationError( message="start must be non-negative", link="http://arxiv.org/api/errors#start_must_be_non-negative", ) # sort by and sort order value = params.get("sortBy", SortBy.relevance) try: sort_by = SortBy(value) except ValueError: raise ValidationError( message=f"sortBy must be in: {', '.join(SortBy)}", link="https://arxiv.org/help/api/user-manual#sort", ) value = params.get("sortOrder", SortDirection.descending) try: sort_direction = SortDirection(value) except ValueError: raise ValidationError( message=f"sortOrder must be in: {', '.join(SortDirection)}", link="https://arxiv.org/help/api/user-manual#sort", ) try: classic_query = ClassicAPIQuery( order=SortOrder(by=sort_by, direction=sort_direction), search_query=search_query, id_list=id_list, size=max_results, page_start=start, ) except ValueError: raise BadRequest( "Either a search_query or id_list must be specified" " for the classic API." ) # pass to search indexer, which will handle parsing document_set: DocumentSet = index.SearchSession.current_session().search( classic_query ) logger.debug( "Got document set with %i results", len(document_set["results"]) ) return ( ClassicSearchResponseData(results=document_set, query=classic_query), HTTPStatus.OK, {}, )