def get(self, request): """ A simple starting implementation for search. TODO: - accept more parameters - scoring on multiple factors - decide on what id to use (MapItem, or [type]:[id], etc.) - and much more... """ def _serialize(hit): """ TODO: Ideally elasticsearch will handle this itself """ return { "id": hit.id, "_meta": { "doc_type": hit.meta.doc_type, }, "locations": [ { "latitude": loc['point']['lat'], "longitude": loc['point']['lon'], } for loc in hit.locations ], } params = request.GET.dict() esq = es_search() q = params.pop("q", None) if q: esq = esq.query("simple_query_string", query=q, fields=["_all"]) # TODO: filter out unnecessary fields # esq = esq.fields() hits = [_serialize(m) for m in esq.execute().hits] return self.success({ "results": hits })
def get(self, request): """ A simple starting implementation for search. TODO: - accept more parameters - scoring on multiple factors - decide on what id to use (MapItem, or [type]:[id], etc.) - and much more... """ def _serialize(hit): """ TODO: Ideally elasticsearch will handle this itself """ return { "id": hit.id, "_meta": { "doc_type": hit.meta.doc_type, }, "locations": [{ "latitude": loc['point']['lat'], "longitude": loc['point']['lon'], } for loc in hit.locations], } params = request.GET.dict() esq = es_search() q = params.pop("q", None) if q: esq = esq.query("simple_query_string", query=q, fields=["_all"]) # TODO: filter out unnecessary fields # esq = esq.fields() hits = [_serialize(m) for m in esq.execute().hits] return self.success({"results": hits})
def get(self, request): """ TODO: - use intelligent ES query to facet across categories instead of grouping with Python """ groups = defaultdict(list) results = [] params = request.GET.dict() esq = es_search() q = params.pop("q", None) nearest = params.pop("nearest", None) radius = params.pop("radius", "100km") if q: esq = esq.query("simple_query_string", query=q, fields=["_all"]) if nearest: lat, lon = map(float, nearest.split(',')) # more weighting is given to closer things # based on https://www.elastic.co/guide/en/elasticsearch/guide/current/decay-functions.html esq = esq.query('function_score', functions=[ { "gauss": { "locations.point": { "origin": { "lat": lat, "lon": lon }, "offset": "0", "scale": radius # something at this radius gets # 50% score of something at the origin } }, "weight": 1 } ]) # collects all the remaining params as metadata filters # TODO: not all metadata should be filterable (some may be private/admin) for key, value in params.items(): esq = esq.filter("term", **{ "metadata.{}".format(key) : value }) print('p', key, value) # faceting on doc type esq.aggs.bucket("doc_type", "terms", field="_type") # TODO: also facet on metadata values... response = esq.execute() hits = response.hits for hit in hits: d = hit.to_dict() d["_meta"] = { k: hit.meta.to_dict()[k] for k in ('score', 'doc_type')} groups[hit.meta['doc_type']].append(d) for category, group in groups.items(): results.append({ "doc_type": category, # TODO: use category name/slug/id "results": group, "total": len(group) # TODO: get real total via faceting }) return self.success({ "result_groups": results, "aggregations": response.aggregations.to_dict() # these are useful if you want to see the raw query/results #"_query": esq.to_dict(), #"_result": response.to_dict() })
def get(self, request): """ TODO: - use intelligent ES query to facet across categories instead of grouping with Python """ groups = defaultdict(list) results = [] params = request.GET.dict() esq = es_search() q = params.pop("q", None) nearest = params.pop("nearest", None) radius = params.pop("radius", "100km") if q: esq = esq.query("simple_query_string", query=q, fields=["_all"]) if nearest: lat, lon = map(float, nearest.split(',')) # more weighting is given to closer things # based on https://www.elastic.co/guide/en/elasticsearch/guide/current/decay-functions.html esq = esq.query( 'function_score', functions=[{ "gauss": { "locations.point": { "origin": { "lat": lat, "lon": lon }, "offset": "0", "scale": radius # something at this radius gets # 50% score of something at the origin } }, "weight": 1 }]) # collects all the remaining params as metadata filters # TODO: not all metadata should be filterable (some may be private/admin) for key, value in params.items(): esq = esq.filter("term", **{"metadata.{}".format(key): value}) print('p', key, value) # faceting on doc type esq.aggs.bucket("doc_type", "terms", field="_type") # TODO: also facet on metadata values... response = esq.execute() hits = response.hits for hit in hits: d = hit.to_dict() d["_meta"] = { k: hit.meta.to_dict()[k] for k in ('score', 'doc_type') } groups[hit.meta['doc_type']].append(d) for category, group in groups.items(): results.append({ "doc_type": category, # TODO: use category name/slug/id "results": group, "total": len(group) # TODO: get real total via faceting }) return self.success({ "result_groups": results, "aggregations": response.aggregations.to_dict() # these are useful if you want to see the raw query/results #"_query": esq.to_dict(), #"_result": response.to_dict() })