def make_search_body(self):
        body = {}
        search = {}

        if self.fuzziness is None:  # beware, could be 0
            fuzziness = getattr(settings, 'ELASTICSEARCH_FUZZINESS', 0.5)
        else:
            fuzziness = self.fuzziness

        if self._query:
            search['query'] = {
                'match': {
                    '_all': {
                        'query': self._query,
                        'fuzziness': fuzziness
                    }
                },
            }

        if self.filters:
            # TODO: should we add _cache = true ?!
            search['filter'] = {}
            mapping = self.model.es.get_mapping()

            for field, value in self.filters.items():
                try:
                    value = value.lower()
                except AttributeError:
                    pass

                field, operator = self.sanitize_lookup(field)

                try:
                    is_nested = 'properties' in mapping[field]
                except KeyError:
                    # abstract
                    is_nested = False

                field_name = is_nested and field + ".id" or field
                if is_nested and isinstance(value, Model):
                    value = value.id

                if operator == 'exact':
                    filtr = {'bool': {'must': [{'term': {field_name: value}}]}}

                elif operator == 'not':
                    filtr = {'bool': {'must_not': [{'term': {field_name: value}}]}}

                elif operator == 'should':
                    filtr = {'bool': {operator: [{'term': {field_name: value}}]}}

                elif operator == 'contains':
                    filtr = {'query': {'match': {field_name: {'query': value}}}}

                elif operator in ['gt', 'gte', 'lt', 'lte']:
                    filtr = {'bool': {'must': [{'range': {field_name: {
                        operator: value}}}]}}

                elif operator == 'range':
                    filtr = {'bool': {'must': [{'range': {field_name: {
                        'gte': value[0],
                        'lte': value[1]}}}]}}

                elif operator == 'isnull':
                    if value:
                        filtr = {'missing': {'field': field_name}}
                    else:
                        filtr = {'exists': {'field': field_name}}

                nested_update(search['filter'], filtr)

            body['query'] = {'filtered': search}
        else:
            body = search

        return body
Example #2
0
    def make_search_body(self):
        body = {}
        search = {}

        if self.fuzziness is None:  # beware, could be 0
            fuzziness = getattr(settings, 'ELASTICSEARCH_FUZZINESS', 0.5)
        else:
            fuzziness = self.fuzziness

        if self._query:
            search['query'] = {
                'match': {
                    '_all': {
                        'query': self._query,
                        'fuzziness': fuzziness
                    }
                },
            }

        if self.filters:
            # TODO: should we add _cache = true ?!
            search['must'] = search['query']
            del(search['query'])
            search['filter'] = {}
            mapping = self.model.es.get_mapping()

            for field, value in self.filters.items():
                try:
                    value = value.lower()
                except AttributeError:
                    pass

                field, operator = self.sanitize_lookup(field)

                try:
                    is_nested = 'properties' in mapping[field]
                except KeyError:
                    # abstract
                    is_nested = False

                field_name = is_nested and field + ".id" or field
                if is_nested and isinstance(value, Model):
                    value = value.id

                if operator == 'exact':
                    filtr = {'bool': {'must': [{'term': {field_name: value}}]}}

                elif operator == 'not':
                    filtr = {'bool': {'must_not': [{'term': {field_name: value}}]}}

                elif operator == 'in':
                    filtr = {'bool': {'must': [{'terms': {field_name: value}}]}}

                elif operator == 'not_in':
                    filtr = {'bool': {'must_not': [{'terms': {field_name: value}}]}}

                elif operator == 'should':
                    filtr = {'bool': {operator: [{'term': {field_name: value}}]}}

                elif operator == 'contains':
                    filtr = {'query': {'match': {field_name: {'query': value}}}}

                elif operator in ['gt', 'gte', 'lt', 'lte']:
                    filtr = {'bool': {'must': [{'range': {field_name: {
                        operator: value}}}]}}

                elif operator == 'range':
                    filtr = {'bool': {'must': [{'range': {field_name: {
                        'gte': value[0],
                        'lte': value[1]}}}]}}

                elif operator == 'isnull':
                    if value:
                        filtr = {'missing': {'field': field_name}}
                    else:
                        filtr = {'exists': {'field': field_name}}

                nested_update(search['filter'], filtr)

            body['query'] = {'bool': search}
        else:
            body = search
        
        return body
Example #3
0
    def make_search_body(self):
        body = {}
        search = {}

        if self.fuzziness is None:  # beware, could be 0
            fuzziness = getattr(settings, "ELASTICSEARCH_FUZZINESS", 0.5)
        else:
            fuzziness = self.fuzziness

        if self._query:
            search["query"] = {"match": {"_all": {"query": self._query, "fuzziness": fuzziness}}}

        if self.filters:
            # TODO: should we add _cache = true ?!
            search["filter"] = {}
            mapping = self.model.es.get_mapping()

            for field, value in self.filters.items():
                try:
                    value = value.lower()
                except AttributeError:
                    pass

                field, operator = self.sanitize_lookup(field)

                try:
                    is_nested = "properties" in mapping[field]
                except KeyError:
                    # abstract
                    is_nested = False

                field_name = is_nested and field + ".id" or field
                if is_nested and isinstance(value, Model):
                    value = value.id

                if operator == "exact":
                    filtr = {"bool": {"must": [{"term": {field_name: value}}]}}

                elif operator == "not":
                    filtr = {"bool": {"must_not": [{"term": {field_name: value}}]}}

                elif operator == "should":
                    filtr = {"bool": {operator: [{"term": {field_name: value}}]}}

                elif operator == "contains":
                    filtr = {"query": {"match": {field_name: {"query": value}}}}

                elif operator in ["gt", "gte", "lt", "lte"]:
                    filtr = {"range": {field_name: {operator: value}}}

                elif operator == "range":
                    filtr = {"range": {field_name: {"gte": value[0], "lte": value[1]}}}

                elif operator == "isnull":
                    if value:
                        filtr = {"missing": {"field": field_name}}
                    else:
                        filtr = {"exists": {"field": field_name}}

                nested_update(search["filter"], filtr)

            body["query"] = {"filtered": search}
        else:
            body = search

        return body
Example #4
0
    def make_search_body(self):
        body = {}
        search = {}

        if self.fuzziness is None:  # beware, could be 0
            fuzziness = getattr(settings, 'ELASTICSEARCH_FUZZINESS', 0.5)
        else:
            fuzziness = self.fuzziness

        if self._query:
            search['query'] = {
                'match': {
                    '_all': {
                        'query': self._query,
                        'fuzziness': fuzziness
                    }
                },
            }

        if self.filters:
            # TODO: should we add _cache = true ?!
            search['filter'] = {}
            # search['query'] = {}
            mapping = self.model.es.get_mapping()
            for field, value in self.filters.items():

                if (field in mapping and 'index' in mapping[field]
                        and mapping[field]['index'] == 'not_analyzed'):
                    # we dont want to lowercase an un-analyzed term search
                    pass
                else:
                    try:
                        value = value.lower()
                    except AttributeError:
                        pass

                field, operator = self.sanitize_lookup(field)

                try:
                    is_nested = 'properties' in mapping[field]
                except KeyError:
                    is_nested = False
                try:
                    is_geo = 'type' in mapping[field] and mapping[field][
                        'type'] == 'geo_point'
                except KeyError:
                    is_geo = False

                field_name = is_nested and field + ".id" or field
                if is_nested and isinstance(value, Model):
                    value = value.id

                if operator == 'exact':
                    filtr = {'bool': {'must': [{'term': {field_name: value}}]}}

                elif operator == 'not':
                    filtr = {
                        'bool': {
                            'must_not': [{
                                'term': {
                                    field_name: value
                                }
                            }]
                        }
                    }

                elif operator in ['should', 'should_not']:
                    filtr = {
                        'bool': {
                            operator: [{
                                'term': {
                                    field_name: value
                                }
                            }]
                        }
                    }

                elif operator == 'contains':
                    filtr = {
                        'query': {
                            'match': {
                                field_name: {
                                    'query': value
                                }
                            }
                        }
                    }

                elif operator in ['gt', 'gte', 'lt', 'lte']:
                    filtr = {'range': {field_name: {operator: value}}}

                elif operator == 'range':
                    filtr = {
                        'range': {
                            field_name: {
                                'gte': value[0],
                                'lte': value[1]
                            }
                        }
                    }

                elif operator == 'isnull':
                    if value:
                        filtr = {'missing': {'field': field_name}}
                    else:
                        filtr = {'exists': {'field': field_name}}

                else:
                    filtr = {
                        'bool': {
                            'must': [{
                                'term': {
                                    field_name + '.' + operator: value
                                }
                            }]
                        }
                    }
                if is_geo:
                    if operator == 'lat':
                        filtr = {'geo_distance': {field_name: {'lat': value}}}
                        self.lat = value
                    elif operator == 'lon':
                        filtr = {'geo_distance': {field_name: {'lon': value}}}
                        self.lng = value
                    elif operator == 'distance':
                        filtr = {'geo_distance': {'distance': value}}
                        self.distance = value
                nested_update(search['filter'],
                              filtr)  # geo_distance only works as filter

            functions = False
            for k, v in search['filter'].iteritems():
                # right now only one geo_distance filter to score on is supported
                if k == 'geo_distance':
                    self.geo_field_name = (key for key in v.keys()
                                           if key != 'distance').next()
                    self.geo_field = v[self.geo_field_name]

                    functions = [{
                        "gauss": {
                            self.geo_field_name: {
                                "origin": self.geo_field,
                                "scale": "20mi",
                                # "offset": "2mi"
                            }
                        }
                    }]
                    break

            if functions:
                # todo, sort by score first then geo?... this is only needed to return distance for each result

                geo = copy.copy(search['filter']['geo_distance'])

                if 'bool' in search['filter']:
                    if 'must' not in search['filter']['bool']:
                        search['filter']['bool']['must'] = []
                    search['filter']['bool']['must'].append(
                        {'geo_distance': geo})
                    del search['filter']['geo_distance']

                body['query'] = {
                    'function_score': {
                        'query': {
                            'filtered': search
                        },
                        'functions': functions
                    }
                }

                # body['sort'] = [
                #
                #   # {'_score': {'order': 'desc'}},
                #   {
                #     '_geo_distance': {
                #       self.geo_field_name: self.geo_field,
                #       'order': 'asc',
                #       'unit': 'mi'
                #     }
                #   }
                # ]

            else:
                body['query'] = {'filtered': search}

        else:
            body = search
        print body
        return body
Example #5
0
    def make_search_body(self):
        body = {}
        search = {}

        if self.fuzziness is None:  # beware, could be 0
            fuzziness = getattr(settings, 'ELASTICSEARCH_FUZZINESS', 0.5)
        else:
            fuzziness = self.fuzziness

        if self._query:
            search['query'] = {
                'match': {
                    '_all': {
                        'query': self._query,
                        'fuzziness': fuzziness
                    }
                },
            }

        if self.filters:
            # TODO: should we add _cache = true ?!
            search['filter'] = {}
            # search['query'] = {}
            mapping = self.model.es.get_mapping()
            for field, value in self.filters.items():

                if (field in mapping and 'index' in mapping[field]
                    and mapping[field]['index'] == 'not_analyzed'):
                  # we dont want to lowercase an un-analyzed term search
                  pass
                else:
                  try:
                      value = value.lower()
                  except AttributeError:
                      pass

                field, operator = self.sanitize_lookup(field)

                try:
                    is_nested = 'properties' in mapping[field]
                except KeyError:
                    is_nested = False
                try:
                  is_geo = 'type' in mapping[field] and mapping[field]['type'] == 'geo_point'
                except KeyError:
                  is_geo = False


                field_name = is_nested and field + ".id" or field
                if is_nested and isinstance(value, Model):
                    value = value.id

                if operator == 'exact':
                    filtr = {'bool': {'must': [{'term': {field_name: value}}]}}

                elif operator == 'not':
                    filtr = {'bool': {'must_not': [{'term': {field_name: value}}]}}

                elif operator in ['should', 'should_not']:
                    filtr = {'bool': {operator: [{'term': {field_name: value}}]}}

                elif operator == 'contains':
                    filtr = {'query': {'match': {field_name: {'query': value}}}}

                elif operator in ['gt', 'gte', 'lt', 'lte']:
                    filtr = {'range': {field_name: {operator: value}}}

                elif operator == 'range':
                    filtr = {'range': {field_name: {
                        'gte': value[0],
                        'lte': value[1]}}}

                elif operator == 'isnull':
                    if value:
                        filtr = {'missing': {'field': field_name}}
                    else:
                        filtr = {'exists': {'field': field_name}}

                else:
                    filtr = {'bool': {'must': [{'term': {
                        field_name + '.' + operator: value}}]}}
                if is_geo:
                  if operator == 'lat':
                    filtr = {'geo_distance': {field_name: {'lat': value}}}
                    self.lat = value
                  elif operator == 'lon':
                    filtr = {'geo_distance': {field_name: {'lon': value}}}
                    self.lng = value
                  elif operator == 'distance':
                    filtr = {'geo_distance': {'distance': value}}
                    self.distance = value
                nested_update(search['filter'], filtr) # geo_distance only works as filter

            functions = False
            for k, v in search['filter'].iteritems():
              # right now only one geo_distance filter to score on is supported
              if k == 'geo_distance':
                self.geo_field_name = (key for key in v.keys()
                              if key != 'distance').next()
                self.geo_field = v[self.geo_field_name]

                functions = [{
                  "gauss": {self.geo_field_name: {
                    "origin": self.geo_field,
                    "scale": "20mi",
                    # "offset": "2mi"
                  }
                  }
                }]
                break

            if functions:
              # todo, sort by score first then geo?... this is only needed to return distance for each result

              geo = copy.copy(search['filter']['geo_distance'])

              if 'bool' in search['filter']:
                if 'must' not in search['filter']['bool']:
                  search['filter']['bool']['must'] = []
                search['filter']['bool']['must'].append({'geo_distance':geo})
                del search['filter']['geo_distance']


              body['query'] = {
                'function_score': {
                  'query':{
                    'filtered': search},
                  'functions': functions
                  }
              }


              # body['sort'] = [
              #
              #   # {'_score': {'order': 'desc'}},
              #   {
              #     '_geo_distance': {
              #       self.geo_field_name: self.geo_field,
              #       'order': 'asc',
              #       'unit': 'mi'
              #     }
              #   }
              # ]

            else:
              body['query'] = {'filtered': search}

        else:
            body = search
        print body
        return body
    def make_search_body(self):
        if self.fuzziness:  # beware, could be 0
            fuzziness = self.fuzziness
        else:
            fuzziness = getattr(settings, 'ELASTICSEARCH_FUZZINESS', 0.5)

        if self._query:
            search_fields = (getattr(self.model.Elasticsearch, 'search_fields',
                                     None) or self.get_search_fields())
            query = {
                'multi_match': {
                    'query': self._query,
                    'fields': search_fields,
                    'fuzziness': fuzziness,
                },
            }

        if self.filters:
            # TODO: should we add _cache = true ?!
            filters = {}
            mapping = self.model.es.make_mapping()

            for field, value in self.filters.items():
                try:
                    value = value.lower()
                except AttributeError:
                    pass

                field, operator = self.sanitize_lookup(field)

                try:
                    is_nested = 'properties' in mapping[field]
                except KeyError:
                    # abstract
                    is_nested = False

                field_name = is_nested and field + ".id" or field
                if is_nested and isinstance(value, Model):
                    value = value.id

                if operator == 'exact':
                    filtr = {
                        'bool': {
                            'filter': [{
                                'term': {
                                    field_name: value
                                }
                            }]
                        }
                    }

                elif operator == 'not':
                    filtr = {
                        'bool': {
                            'must_not': [{
                                'term': {
                                    field_name: value
                                }
                            }]
                        }
                    }

                elif operator == 'should':
                    filtr = {
                        'bool': {
                            'should': [{
                                'term': {
                                    field_name: value
                                }
                            }]
                        }
                    }

                elif operator == 'contains':
                    filtr = {
                        'query': {
                            'match': [{
                                field_name: {
                                    'query': value
                                }
                            }]
                        }
                    }

                elif operator in ['gt', 'gte', 'lt', 'lte']:
                    filtr = {
                        'bool': {
                            'must': [{
                                'range': {
                                    field_name: {
                                        operator: value
                                    }
                                }
                            }]
                        }
                    }

                elif operator == 'range':
                    filtr = {
                        'bool': {
                            'must': [{
                                'range': {
                                    field_name: {
                                        'gte': value[0],
                                        'lte': value[1]
                                    }
                                }
                            }]
                        }
                    }

                elif operator == 'isnull':
                    if value:
                        filtr = {'missing': {'field': field_name}}
                    else:
                        filtr = {'exists': {'field': field_name}}

                nested_update(filters, filtr)

            body = {'query': {'bool': {'must': query}}}
            for filter_type, value in filters.items():
                body['query'].setdefault(filter_type, {})
                body['query'][filter_type].update(value)

        else:
            body = {'query': query}

        return body
Example #7
0
    def make_search_body(self):
        es_version = es_client.info()['version']['number']
        legacy_mode = LooseVersion(es_version) < LooseVersion('2.0.0')

        filtered_or_bool = 'filtered' if legacy_mode else 'bool'
        query_or_must = 'query' if legacy_mode else 'must'

        body = {}
        query = {}

        if self.fuzziness is None:  # beware, could be 0
            fuzziness = getattr(settings, 'ELASTICSEARCH_FUZZINESS', 0.5)
        else:
            fuzziness = self.fuzziness

        if self._query:
            query = {
                'match': {
                    '_all': {
                        'query': self._query,
                        'fuzziness': fuzziness
                    }
                },
            }

        if self.filters:
            # TODO: should we add _cache = true ?!
            filters = {}
            mapping = self.model.es.get_mapping()

            for field, value in self.filters.items():
                field, operator = self.sanitize_lookup(field)

                try:
                    is_nested = 'properties' in mapping[field]
                except KeyError:
                    # abstract
                    is_nested = False

                field_name = field + ".id" if is_nested else field
                if is_nested and isinstance(value, Model):
                    value = value.id

                if operator == 'in':
                    nested_update(
                        filters, {
                            query_or_must: {
                                filtered_or_bool: {
                                    "filter": {
                                        'terms': {
                                            field_name: value
                                        }
                                    }
                                }
                            }
                        })
                    if len(
                            list(filters[query_or_must][filtered_or_bool]
                                 ["filter"]['terms'].items())) > 1:
                        raise NotImplementedError(
                            "multi_terms is not implemented.")
                elif operator == 'contains':
                    nested_update(
                        filters,
                        {'query': {
                            'match': {
                                field_name: {
                                    'query': value
                                }
                            }
                        }})
                    if len(list(filters['query']['match'].items())) > 1:
                        raise NotImplementedError(
                            "multi_match is not implemented.")
                elif operator == 'isnull':
                    if value:
                        filtr = {'missing': {'field': field_name}}
                    else:
                        filtr = {'exists': {'field': field_name}}

                    nested_update(filters, {'filter': filtr})

                else:
                    if operator == 'exact':
                        filtr = {'must': [{'term': {field_name: value}}]}

                    elif operator == 'not':
                        filtr = {'must_not': [{'term': {field_name: value}}]}

                    elif operator == 'should':
                        filtr = {operator: [{'term': {field_name: value}}]}

                    elif operator in ['gt', 'gte', 'lt', 'lte']:
                        filtr = {
                            'must': [{
                                'range': {
                                    field_name: {
                                        operator: value
                                    }
                                }
                            }]
                        }

                    elif operator == 'range':
                        filtr = {
                            'must': [{
                                'range': {
                                    field_name: {
                                        'gte': value[0],
                                        'lte': value[1]
                                    }
                                }
                            }]
                        }

                    nested_update(filters, {'filter': {'bool': filtr}})

            body = {'query': {filtered_or_bool: filters}}
            if query:
                body['query'][filtered_or_bool][query_or_must] = query
        else:
            if query:
                body = {'query': query}

        return body