示例#1
0
 def add_items_update_then_create(self, content_type_pk, objs):
     config = self.backend.config
     ids_and_objs = {}
     for obj in objs:
         obj._autocomplete_ = (ADD([
             SearchVector(Value(text), weight=weight, config=config)
             for text, weight in obj._autocomplete_
         ]) if obj._autocomplete_ else EMPTY_VECTOR)
         obj._body_ = (ADD([
             SearchVector(Value(text), weight=weight, config=config)
             for text, weight in obj._body_
         ]) if obj._body_ else EMPTY_VECTOR)
         ids_and_objs[obj._object_id_] = obj
     index_entries_for_ct = self.entries.filter(
         content_type_id=content_type_pk)
     indexed_ids = frozenset(
         index_entries_for_ct.filter(
             object_id__in=ids_and_objs).values_list('object_id',
                                                     flat=True))
     for indexed_id in indexed_ids:
         obj = ids_and_objs[indexed_id]
         index_entries_for_ct.filter(object_id=obj._object_id_) \
             .update(autocomplete=obj._autocomplete_, body=obj._body_)
     to_be_created = []
     for object_id in ids_and_objs:
         if object_id not in indexed_ids:
             obj = ids_and_objs[object_id]
             to_be_created.append(
                 IndexEntry(content_type_id=content_type_pk,
                            object_id=object_id,
                            autocomplete=obj._autocomplete_,
                            body=obj._body_))
     self.entries.bulk_create(to_be_created)
示例#2
0
    def search(self, config, start, stop):
        # TODO: Handle MatchAll nested inside other search query classes.
        if isinstance(self.query, MatchAll):
            return self.queryset[start:stop]

        search_query = self.build_database_query(config=config)
        queryset = self.queryset
        query = queryset.query
        if self.fields is None:
            vector = F('index_entries__body_search')
        else:
            vector = ADD(
                SearchVector(field,
                             config=search_query.config,
                             weight=get_weight(self.get_boost(field)))
                for field in self.fields)
        vector = vector.resolve_expression(query)
        search_query = search_query.resolve_expression(query)
        lookup = IndexEntry._meta.get_field('body_search').get_lookup('exact')(
            vector, search_query)
        query.where.add(lookup, 'AND')
        if self.order_by_relevance:
            # Due to a Django bug, arrays are not automatically converted here.
            converted_weights = '{' + ','.join(map(str, WEIGHTS_VALUES)) + '}'
            queryset = queryset.order_by(
                SearchRank(vector, search_query,
                           weights=converted_weights).desc(), '-pk')
        elif not queryset.query.order_by:
            # Adds a default ordering to avoid issue #3729.
            queryset = queryset.order_by('-pk')
        return queryset[start:stop]
示例#3
0
    def search(self, config, start, stop):
        # TODO: Handle MatchAll nested inside other search query classes.
        if isinstance(self.query, MatchAll):
            return self.queryset[start:stop]

        search_query = self.build_database_query(config=config)
        queryset = self.queryset
        query = queryset.query
        if self.fields is None:
            vector = F('index_entries__body_search')
        else:
            vector = ADD(
                SearchVector(field, config=search_query.config,
                             weight=get_weight(self.get_boost(field)))
                for field in self.fields)
        vector = vector.resolve_expression(query)
        search_query = search_query.resolve_expression(query)
        lookup = IndexEntry._meta.get_field('body_search').get_lookup('exact')(
            vector, search_query)
        query.where.add(lookup, 'AND')
        if self.order_by_relevance:
            # Due to a Django bug, arrays are not automatically converted here.
            converted_weights = '{' + ','.join(map(str, WEIGHTS_VALUES)) + '}'
            queryset = queryset.order_by(SearchRank(vector, search_query,
                                                    weights=converted_weights).desc(),
                                         '-pk')
        elif not queryset.query.order_by:
            # Adds a default ordering to avoid issue #3729.
            queryset = queryset.order_by('-pk')
        return queryset[start:stop]
    def build_tsrank(self, vector, query, config=None, boost=1.0):
        if isinstance(query, (Phrase, PlainText, Not)):
            rank_expression = SearchRank(vector,
                                         self.build_tsquery(query,
                                                            config=config),
                                         weights=self.sql_weights)

            if boost != 1.0:
                rank_expression *= boost

            return rank_expression

        elif isinstance(query, Boost):
            boost *= query.boost
            return self.build_tsrank(vector,
                                     query.subquery,
                                     config=config,
                                     boost=boost)

        elif isinstance(query, And):
            return MUL(
                1 +
                self.build_tsrank(vector, subquery, config=config, boost=boost)
                for subquery in query.subqueries) - 1

        elif isinstance(query, Or):
            return ADD(
                self.build_tsrank(vector, subquery, config=config, boost=boost)
                for subquery in query.subqueries) / (len(query.subqueries)
                                                     or 1)

        raise NotImplementedError(
            '`%s` is not supported by the PostgreSQL search backend.' %
            query.__class__.__name__)
示例#5
0
    def search(self, config, start, stop, score_field=None):
        # TODO: Handle MatchAll nested inside other search query classes.
        if isinstance(self.query, MatchAll):
            return self.queryset[start:stop]

        search_query = self.build_database_query(config=config)
        if self.fields is None:
            vector = F('index_entries__autocomplete')
            if not self.is_autocomplete:
                vector = vector._combine(F('index_entries__body'), '||', False)
        else:
            vector = ADD(
                SearchVector(field_lookup,
                             config=search_query.config,
                             weight=get_weight(search_field.boost))
                for field_lookup, search_field in self.search_fields.items()
                if not self.is_autocomplete or search_field.partial_match)
        rank_expression = SearchRank(vector,
                                     search_query,
                                     weights=self.sql_weights)
        queryset = self.queryset.annotate(_vector_=vector).filter(
            _vector_=search_query)
        if self.order_by_relevance:
            queryset = queryset.order_by(rank_expression.desc(), '-pk')
        elif not queryset.query.order_by:
            # Adds a default ordering to avoid issue #3729.
            queryset = queryset.order_by('-pk')
            rank_expression = F('pk')
        if score_field is not None:
            queryset = queryset.annotate(**{score_field: rank_expression})
        return queryset[start:stop]
示例#6
0
 def get_fields_vector(self, search_query):
     return ADD(
         SearchVector(field_lookup,
                      config=search_query.config,
                      weight=get_weight(search_field.boost))
         for field_lookup, search_field in self.search_fields.items()
         if search_field.partial_match)
示例#7
0
 def get_fields_vector(self, search_query):
     return ADD(
         SearchVector(
             field_lookup,
             config=search_query.config,
             weight='D',
         ) for field_lookup, search_field in self.search_fields.items())
示例#8
0
 def add_items_update_then_create(self, content_type_pk, objs, config):
     ids_and_objs = {}
     for obj in objs:
         obj._search_vector = (ADD([
             SearchVector(Value(text), weight=weight, config=config)
             for text, weight in obj._body_
         ]) if obj._body_ else SearchVector(Value('')))
         ids_and_objs[obj._object_id] = obj
     index_entries_for_ct = self.index_entries.filter(
         content_type_id=content_type_pk)
     indexed_ids = frozenset(
         index_entries_for_ct.filter(
             object_id__in=ids_and_objs).values_list('object_id',
                                                     flat=True))
     for indexed_id in indexed_ids:
         obj = ids_and_objs[indexed_id]
         index_entries_for_ct.filter(object_id=obj._object_id) \
             .update(body_search=obj._search_vector)
     to_be_created = []
     for object_id in ids_and_objs:
         if object_id not in indexed_ids:
             to_be_created.append(
                 IndexEntry(
                     content_type_id=content_type_pk,
                     object_id=object_id,
                     body_search=ids_and_objs[object_id]._search_vector,
                 ))
     self.index_entries.bulk_create(to_be_created)
示例#9
0
    def as_vector(self, texts):
        """
        Converts an array of strings into a SearchVector that can be indexed.
        """
        if not texts:
            return EMPTY_VECTOR

        return ADD([
            SearchVector(Value(text, output_field=TextField()),
                         weight=weight,
                         config=self.search_config) for text, weight in texts
        ])
示例#10
0
    def as_vector(self, texts, for_autocomplete=False):
        """
        Converts an array of strings into a SearchVector that can be indexed.
        """
        if not texts:
            return EMPTY_VECTOR

        search_config = self.autocomplete_config if for_autocomplete else self.config

        return ADD([
            SearchVector(Value(text, output_field=TextField()),
                         weight=weight,
                         config=search_config) for text, weight in texts
        ])