barseghyanartur/django-elasticsearch-dsl-drf

How to use ngram in search query param

bplociennik opened this issue · 2 comments

Questions

I'm trying to add ngrams to one of my fields title to use directly in the search query param. I would like to be able to find objects even by part of my name.

I tried examples on the repository and attached code in the advanced section in the documentation but I cannot figure out what I'm doing wrong.

I don't have deep knowledge about Elasticsearch so it may be problematic that I'm using an analyzer or normalizer in the wrong way.

For example, I have a product with the title "product long-description" I would like to get this product when I search (?search=value) for some parts of this title like "long", "description", "long description", "product long" etc.

documents.py:

edge_ngram_completion_filter = token_filter(
    'edge_ngram_completion_filter',
    type="edge_ngram",
    min_gram=3,
    max_gram=20
)

edge_ngram_completion = analyzer(
    "edge_ngram_completion",
    tokenizer="standard",
    filter=["lowercase", edge_ngram_completion_filter],
    char_filter=["html_strip"],
)


@INDEX.doc_type
class ProductDocument(Document):
    title = fields.TextField(
        analyzer=edge_ngram_completion,
        fields={"raw": KeywordField(normalizer=lowercase_normalizer)}
    )

views.py:

class ProductDocumentViewSet(BaseDocumentViewSet):
    document = ProductDocument
    filter_backends = [
        FilteringFilterBackend,
        OrderingFilterBackend,
        CompoundSearchFilterBackend,
        NestedFilteringFilterBackend,
        DefaultOrderingFilterBackend,
    ]
    filter_fields = {
        "id": None,
        "title": {
            "field": "title.raw", "lookups": [
                LOOKUP_FILTER_TERMS,
                LOOKUP_FILTER_PREFIX,
                LOOKUP_FILTER_WILDCARD,
                LOOKUP_QUERY_IN,
                LOOKUP_QUERY_EXCLUDE,
            ],
            },
    }
    search_fields = {"title": {"boost": 25}, "description": None}
    ordering_fields = {
        "id": None,
        "title": "title.raw",
    }

PS. Thanks for the great packages it helped me a lot to save a lot of time and hairs :D

you are right, thanks :)