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
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
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
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): 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
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