def _build_exists_query(field, value): """Builds an exists query.""" real_field = field[:field.rindex('_')] kind = 'must' if value else 'must_not' query = { kind: Exists(field=real_field), } return Bool(**query)
def get_query_condition(self, url_parameter, field, value): """ Return an ElasticSearch DSL query object with the appropriate settings for its kind and values from the given url_parameter. :param url_parameter: String of the URL parameter for this query. :param field: String of the ElasticSearch document field to search. :param value: Raw value to look for in this query. :returns: Some kind of Query child class. """ settings = self.query_parameters.get(url_parameter) if not settings: raise KeyError("Parameter %s has no query parameters defined." % url_parameter) # The resultant query_class_parameters dictionary looks something like: # { # 'query_key': 'value', # 'fields': ['foo', 'bar', 'baz'], # } # Attributes is the leftover **kwargs from the original function call. # query_class_parameters = {**{settings.get('query_key'): value}, **settings.get('attributes')} if settings.get('query_class') is Wildcard: search_value = "*%s*" % value return Wildcard(**{field: {'value': search_value}}) elif settings.get('query_class') is MatchPhrase: return MatchPhrase(**{field: value}) elif settings.get('query_class') is Prefix: # If you're having problems with Prefix queries, see if the # whitespace analyzer is set! See the RecipeIndex class for more. return Prefix(**{field: {'value': value}}) elif settings.get('query_class') is Match: return Match(**{field: {'query': value}}) elif settings.get('query_class') is Exists: return Exists(**{'field': field}) elif settings.get('query_class') is Range: # This is some hacks to simplify URL queries. This may be a bad idea. # Range() queries do not support 'eq' (use Match() for that). To cheat # this in my interface if something sets this a key of 'eq' then we # under the hood convert this to a Match query. if 'eq' in value.keys(): return Match(**{field: {'query': value.get('eq')}}) return Range(**{field: value}) else: raise KeyError("Unsupported query class")
def translate_clause(self, clause, field): if ("constraint" in clause): match_params = {} query_type = clause.get("query_type", "match") match_field_params = {} match_field_params["query"] = clause["constraint"] #match_field_params["type"] = query_type match_field_params["boost"] = field.get("weight", 1.0) match_field_params["_name"] = "{}:{}:{}".format( clause.get("_id"), field.get("name"), clause.get("constraint")) match_params[field["name"]] = match_field_params if query_type == "match_phrase": match_params_mp = {} match_field_params_mp = copy.copy(match_field_params) match_field_params_mp[ "boost"] = match_field_params_mp["boost"] * len( clause.get("constraint").split(" ")) match_field_params_mp[ "_name"] = match_field_params_mp["_name"] + ":match_phrase" match_params_mp[field["name"]] = match_field_params_mp match_field_params_mp["slop"] = 10 mp = MatchPhrase(**match_params_mp) m = Match(**match_params) return Bool(must=[m], should=[mp]) else: if "date" in clause.get("type", "owl:Thing").lower(): match_field_params.pop("query", None) if re.match("\d\d\d\d-\d\d-\d\d", clause["constraint"]): match_field_params["gte"] = clause["constraint"] else: match_field_params["gte"] = "{}||/d".format( clause["constraint"]) match_field_params["lt"] = "{}||+1d/d".format( clause["constraint"]) return Range(**match_params) elif clause.get("type", "owl:Thing") == "owl:Thing": match_field_params["boost"] = field.get("weight", 1.0) * 2 return Match(**match_params) else: return Exists(field=field["name"])
]), ]), ), ( "municipalities", "gt|population|42108", Bool(should=[ Range(population={"gt": 42108}), Range(population__value__total={"gt": 42108}), ]), ), ( "places", "exists|state", Bool(should=[ Exists(field="state"), Exists(field="v_municipality.state") ]), ), ( "places", "exists||or|state|name", Bool(should=[ Exists(field="state"), Exists(field="name"), Exists(field="v_municipality.state"), ]), ), ( "places", "exists||and|state|name",
def get_query_conditions(self, url_parameter, fields, value): """ Return a list of ElasticSearch DSL query objects with the appropriate settings for its kind and values from the given url_parameter. :param url_parameter: String of the URL parameter for this query. :param fields: List[String] of the ElasticSearch document fields to search. :param value: Raw value to look for in this query. :returns: Some kind of Query child class. """ settings = self.query_parameters.get(url_parameter) if not settings: raise KeyError("Parameter %s has no query parameters defined." % url_parameter) # The resultant query_class_parameters dictionary looks something like: # { # 'query_key': 'value', # 'fields': ['foo', 'bar', 'baz'], # } # Attributes is the leftover **kwargs from the original function call. # query_class_parameters = {**{settings.get('query_key'): value}, **settings.get('attributes')} conditions = [] # QueryClasses that take all fields at once get constructed here. # https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html if settings.get('query_class') is MultiMatch: conditions.append(MultiMatch(**{'query': value, 'fields': fields})) return conditions # For the rest, cycle through each field and build an object for each of them. for field in fields: if settings.get('query_class') is Wildcard: search_value = "*%s*" % value conditions.append(Wildcard(**{field: {'value': search_value}})) elif settings.get('query_class') is MatchPhrase: conditions.append(MatchPhrase(**{field: value})) elif settings.get('query_class') is Prefix: # If you're having problems with Prefix queries, see if the # whitespace analyzer is set! See the RecipeIndex class for more. conditions.append(Prefix(**{field: {'value': value}})) elif settings.get('query_class') is Match: conditions.append(Match(**{field: {'query': value}})) elif settings.get('query_class') is Exists: conditions.append(Exists(**{'field': field})) elif settings.get('query_class') is Range: # This is some hacks to simplify URL queries. This may be a bad idea. # Range() queries do not support 'eq' (use Match() for that). To cheat # this in my interface if something sets this a key of 'eq' then we # under the hood convert this to a Match query. if 'eq' in value.keys(): conditions.append( Match(**{field: { 'query': value.get('eq') }})) else: conditions.append(Range(**{field: value})) # Since MultiMatch takes all fields at once, it is constructed outside of this area. else: raise KeyError("Unsupported query class") # Return the list return conditions