예제 #1
0
def test_geo():
    # Geo location search is not supported yet.
    # Links:
    #  - https://cloud.google.com/appengine/docs/standard/python/search/query_strings#Python_Queries_on_geopoint_fields (GAE)
    #  - https://lucene.apache.org/solr/guide/7_6/spatial-search.html (Solr).
    prepare_solr_query('distance(location, geopoint(35.2, 40.5)) < 100',
                       FIELDS, GROUPED_FIELDS)
예제 #2
0
def test_bool_operator_priorities():
    solr_query_options = prepare_solr_query('NOT cat AND dogs OR horses',
                                            FIELDS, GROUPED_FIELDS)
    assert solr_query_options.query_string == \
           '(NOT "cat" AND ("dogs" OR "horses"))'

    solr_query_options = prepare_solr_query('NOT cat OR dogs AND horses',
                                            FIELDS, GROUPED_FIELDS)
    assert solr_query_options.query_string == \
           '((NOT "cat" OR "dogs") AND "horses")'
예제 #3
0
def test_field_match_any_value():
    # Value like number OR value like date
    solr_query_options = prepare_solr_query(
        'description:(-123.6 OR 1999-08-15)', FIELDS, GROUPED_FIELDS)
    assert solr_query_options.query_string == (
        '((description_txt_en:"-123.6" OR description_txt_fr:"-123.6" OR'
        ' description_number:"-123.6") OR '
        '(description_txt_en:"1999-08-15" OR description_txt_fr:"1999-08-15" OR'
        ' description_date:"1999-08-15"))')
    assert solr_query_options.query_fields == []
예제 #4
0
def test_single_word():
    solr_query_options = prepare_solr_query('foo', FIELDS, GROUPED_FIELDS)
    assert solr_query_options.query_string == '"foo"'
    assert set(solr_query_options.query_fields) == {
        'tag_atom',
        'name_atom',
        'description_txt_en',
        'description_txt_fr',
    }
    assert solr_query_options.def_type == 'edismax'
예제 #5
0
def test_word_and_word():
    solr_query_options = prepare_solr_query('hello AND world', FIELDS,
                                            GROUPED_FIELDS)
    assert solr_query_options.query_string == '("hello" AND "world")'
    assert set(solr_query_options.query_fields) == {
        'tag_atom',
        'name_atom',
        'description_txt_en',
        'description_txt_fr',
    }
예제 #6
0
def test_single_number():
    solr_query_options = prepare_solr_query('-123.4', FIELDS, GROUPED_FIELDS)
    assert solr_query_options.query_string == '"-123.4"'
    assert set(solr_query_options.query_fields) == {
        'tag_atom',
        'name_atom',
        'description_txt_en',
        'description_txt_fr',
        'description_number',
        'price_number',
    }
예제 #7
0
def test_quoted():
    solr_query_options = prepare_solr_query(
        '"tag:hello AND whateve OR (it does NOT matter)"', FIELDS,
        GROUPED_FIELDS)
    assert solr_query_options.query_string == \
      '"tag:hello AND whateve OR (it does NOT matter)"'
    assert set(solr_query_options.query_fields) == {
        'tag_atom',
        'name_atom',
        'description_txt_en',
        'description_txt_fr',
    }
예제 #8
0
def test_word_and_word_or_number():
    solr_query_options = prepare_solr_query('hello AND world OR 321.6', FIELDS,
                                            GROUPED_FIELDS)
    assert solr_query_options.query_string == '("hello" AND ("world" OR "321.6"))'
    assert set(solr_query_options.query_fields) == {
        'tag_atom',
        'name_atom',
        'description_txt_en',
        'description_txt_fr',
        'description_number',
        'price_number',
    }
예제 #9
0
def test_field_compare():
    solr_query_options = prepare_solr_query(
        'description>100.2 description<=200 price<999.9 price>=100 '
        'created_at>=1990-06-13', FIELDS, GROUPED_FIELDS)
    assert solr_query_options.query_string == (
        '(description_number:{"100.2" TO *] AND description_number:[* TO "200"]'
        ' AND price_number:[* TO "999.9"} AND price_number:["100" TO *]'
        ' AND created_at_date:["1990-06-13" TO *])'
        # Searching date on description_number would lead to error,
        # so it should be skipped.
    )
    assert solr_query_options.query_fields == []
예제 #10
0
def test_two_words():
    solr_query_options = prepare_solr_query('hello world', FIELDS,
                                            GROUPED_FIELDS)
    # It's currently expected to fail as we convert it to '"hello" AND "world"'
    # Links:
    #  - https://cloud.google.com/appengine/docs/standard/python/search/query_strings#Python_Multi-value_queries
    assert solr_query_options.query_string == '"hello world"'
    assert set(solr_query_options.query_fields) == {
        'tag_atom',
        'name_atom',
        'description_txt_en',
        'description_txt_fr',
    }
예제 #11
0
def test_field_with_many_types():
    # Value like number
    solr_query_options = prepare_solr_query('description:-123.6', FIELDS,
                                            GROUPED_FIELDS)
    assert solr_query_options.query_string == (
        '(description_txt_en:"-123.6" OR description_txt_fr:"-123.6" OR'
        ' description_number:"-123.6")'
        # Searching number on description_date would lead to error,
        # so it should be skipped.
    )
    assert solr_query_options.query_fields == []

    # Value like date
    solr_query_options = prepare_solr_query('description:1999-08-15', FIELDS,
                                            GROUPED_FIELDS)
    assert solr_query_options.query_string == (
        '(description_txt_en:"1999-08-15" OR description_txt_fr:"1999-08-15" OR'
        ' description_date:"1999-08-15")'
        # Searching date on description_number would lead to error,
        # so it should be skipped.
    )
    assert solr_query_options.query_fields == []
예제 #12
0
def test_single_date():
    solr_query_options = prepare_solr_query('2019-01-23', FIELDS,
                                            GROUPED_FIELDS)
    assert solr_query_options.query_string == '"2019-01-23"'
    assert set(solr_query_options.query_fields) == {
        'tag_atom',
        'name_atom',
        'description_txt_en',
        'description_txt_fr',
        'description_date',
        'created_at_date',
        'modified_at_date',
    }
예제 #13
0
def test_date_and_word_or_number():
    solr_query_options = prepare_solr_query('2019-02-02 AND world OR 321.6',
                                            FIELDS, GROUPED_FIELDS)
    assert solr_query_options.query_string == \
      '("2019-02-02" AND ("world" OR "321.6"))'
    assert set(solr_query_options.query_fields) == {
        'tag_atom',
        'name_atom',
        'description_txt_en',
        'description_txt_fr',
        'description_number',
        'description_date',
        'created_at_date',
        'modified_at_date',
        'price_number',
    }
예제 #14
0
def test_complex_composition():
    solr_query_options = prepare_solr_query(
        'name:(-123.6 OR 1999-08-15 AND (foo AND NOT bar dogs (hello))) '
        'AND tag:phone "some () quoted text NOT 123" '
        'OR (one two OR three) OR price>321.6', FIELDS, GROUPED_FIELDS)
    assert solr_query_options.query_string == (
        '(((name_atom:"-123.6" OR name_atom:"1999-08-15") AND '
        '(name_atom:"foo" AND NOT name_atom:"bar" AND name_atom:"dogs" AND '
        'name_atom:"hello")) AND '
        'tag_atom:"phone" AND ("some () quoted text NOT 123" OR '
        '("one" AND ("two" OR "three")) OR '
        'price_number:{"321.6" TO *]))')
    assert set(solr_query_options.query_fields) == {
        'tag_atom',
        'name_atom',
        'description_txt_en',
        'description_txt_fr',
    }
예제 #15
0
    async def query(self, app_id, namespace, index_name, query,
                    projection_fields, sort_expressions, limit, offset, cursor,
                    keys_only, auto_discover_facet_count, facet_requests,
                    facet_refinements, facet_auto_detect_limit):
        """ Retrieves documents which matches query from Solr collection
    and converts it to unified documents.

    Args:
      app_id: a str representing Application ID.
      namespace: a str representing GAE namespace or None.
      index_name: a str representing name of Search API index.
      query: a str containing Search API query.
      projection_fields: a list of field names to return in results.
      sort_expressions: a list of sort expressions, e.g.: ("field1", "asc").
      limit: an int specifying maximum number of results to return.
      offset: an int specifying number of first document to skip.
      cursor: a str representing query cursor.
      keys_only: a bool indicating if only document IDs should be returned.
      auto_discover_facet_count: An int - number of top facets to discover.
      facet_requests: A list of FacetRequest.
      facet_refinements: A list of FacetRefinement.
      facet_auto_detect_limit: An int - number of top terms to return.
    Returns (asynchronously):
      An instance of models.SearchResult.
    """
        index_schema = await self._get_schema_info(app_id, namespace,
                                                   index_name)
        # Convert Search API query to Solr query with a list of fields to search.
        query_options = query_converter.prepare_solr_query(
            query, index_schema.fields, index_schema.grouped_fields)
        # Process GAE projection fields
        solr_projection_fields = self._convert_projection(
            keys_only, projection_fields, index_schema)
        # Process GAE sort expressions
        solr_sort_fields = self._convert_sort_expressions(
            sort_expressions, index_schema)
        # Process GAE facet-related parameters
        refinement_filter = None
        if facet_refinements:
            # Determine if we need to filter by refinement.
            refinement_filter = facet_converter.generate_refinement_filter(
                index_schema.grouped_facet_indexes, facet_refinements)
        facet_items, stats_items = await self._convert_facet_args(
            auto_discover_facet_count, facet_auto_detect_limit, facet_requests,
            index_schema, query_options, refinement_filter)
        stats_fields = [stats_line for solr_field, stats_line in stats_items]

        # DO ACTUAL QUERY:
        solr_result = await self.solr.query_documents(
            collection=index_schema.collection,
            query=query_options.query_string,
            offset=offset,
            limit=limit,
            cursor=cursor,
            fields=solr_projection_fields,
            sort=solr_sort_fields,
            def_type=query_options.def_type,
            query_fields=query_options.query_fields,
            facet_dict=dict(facet_items) if facet_items else None,
            stats_fields=stats_fields or None,
            filter_=refinement_filter)

        # Convert Solr results to unified models
        docs = [
            _from_solr_document(solr_doc) for solr_doc in solr_result.documents
        ]
        # Read stats results
        stats_results = []
        for solr_field, stats_line in stats_items:
            stats_info = solr_result.stats_results[solr_field.solr_name]
            stats_results.append((solr_field.gae_name, stats_info))
        # Convert facet results from Solr facets and stats
        facet_results = facet_converter.convert_facet_results(
            solr_result.facet_results, stats_results)
        result = SearchResult(num_found=solr_result.num_found,
                              scored_documents=docs,
                              cursor=cursor,
                              facet_results=facet_results)
        return result
예제 #16
0
def test_stem_text():
    solr_query_options = prepare_solr_query('~hello', FIELDS, GROUPED_FIELDS)
    assert solr_query_options.query_string == '"hello"~'
예제 #17
0
def test_field_quoted_value():
    solr_query_options = prepare_solr_query('tag:"hello"', FIELDS,
                                            GROUPED_FIELDS)
    assert solr_query_options.query_string == 'tag_atom:"hello"'
    assert solr_query_options.query_fields == []