def autocomplete_search(q, doc_type=None, fuzzy_mode=False, **kwargs): query = autocomplete_query(q, fuzzy_mode) limit = kwargs.get('limit', 20) offset = kwargs.get('offset', 0) filters = kwargs.get('filters', {}) if limit and limit > 100: limit = 100 s = Search().index('_all') if doc_type: s = s.doc_type(doc_type) s = s.query('match', autocomplete=query) # TODO: implement in a generic way # add filters like: `&filter_status=Ready&filter_type=Broadcasts` for key, value in filters.iteritems(): s = s.query('term', **{key: value[0]}) s = s[offset:limit + offset] return format_search_results(s.execute())
def autocomplete(query: str) -> Response: """ https://www.elastic.co/guide/en/elasticsearch/guide/current/_index_time_search_as_you_type.html We use the ngram-based autocomplete-analyzer for indexing, but the standard analyzer for searching This way we enforce that the whole entered word has to be matched (save for some fuzziness) and the algorithm does not fall back to matching only the first character in extreme cases. This prevents absurd cases where "Garret Walker" and "Hector Mendoza" are suggested when we're entering "Mahatma Ghandi" """ search_query = Search(index=list(DOCUMENT_INDICES.values())) search_query = search_query.query( "match", autocomplete={ "query": escape_elasticsearch_query(query), "analyzer": "standard", "fuzziness": "AUTO", "prefix_length": 1, }, ) search_query = search_query.extra(min_score=1) search_query = search_query.update_from_dict({ "indices_boost": [ { DOCUMENT_INDICES["person"]: 4 }, { DOCUMENT_INDICES["organization"]: 4 }, { DOCUMENT_INDICES["paper"]: 2 }, ] }) response = search_query.execute() return response
def query(self, search: Search, query: str) -> Search: if query: self.options["searchterm"] = query # Fuzzines AUTO(=2) gives more error tolerance, but is also a lot slower and has many false positives # We're using https://stackoverflow.com/a/35375562/3549270 to make exact matches score higher than fuzzy # matches search = search.query( Bool(should=[ MultiMatch( query=escape_elasticsearch_query(query), operator="and", fields=self.fields, ), MultiMatch( query=escape_elasticsearch_query(query), operator="and", fields=self.fields, fuzziness="1", prefix_length=1, ), ])) return search