Частичное сопоставление DSL Django ElasticSearch с помощью анализатора nGram
Я совсем новичок в теме ElasticSearch и пытаюсь реализовать простой поиск электронной коммерции в моем Django приложении, используя ElasticSearch с библиотекой django-elasticsearch-dsl
Github repo .
Я пытаюсь (крайне упрощенно) добиться того, чтобы, рассматривая эти экземпляры модели Django:
Red T-shirts
Blue T-Shirts
Nice T-Shirts
для поискового запроса T-Sh
я получу все эти три результата:
Red T-shirts
Blue T-Shirts
Nice T-Shirts
Итак, у меня есть такая модель в shop/models.py (опять же очень упрощенная)
class Category(models.Model):
title = models.CharField(max_length=150, blank=False)
description = models.CharField(max_length=150, blank=False)
# In reality here I have more fields
def __str__(self):
return self.title
Вот shop/documents.py
from elasticsearch_dsl import analyzer, tokenizer
autocomplete_analyzer = analyzer('autocomplete_analyzer',
tokenizer=tokenizer('trigram', 'nGram', min_gram=1, max_gram=20),
filter=['lowercase']
)from elasticsearch_dsl import analyzer, tokenizer
@registry.register_document
class CategoryDocument(Document):
title: fields.TextField(analyzer=autocomplete_analyzer, search_analyzer='standard') # Here I'm trying to use the analyzer specified above
class Index:
name = 'categories'
settings = {
'number_of_shards': 1,
'number_of_replicas': 0,
'max_ngram_diff': 20 # This seems to be important due to the constraint for max_ngram_diff beeing 1
}
class Django:
model = Category
fields = [
'title',
# In reality here I have more fields
]
И наконец, мой shop/views.py
class CategoryElasticSearch(ListView):
def get(self, request, lang):
search_term = request.GET.get('search_term', '')
q = Q(
"multi_match",
query=search_term,
fields=[
'title',
# In reality here I have more fields
],
fuzziness='auto',)
search = search.query(q)
# ... etc
Но результат для T-Sh
пуст. Я получаю что-то только когда пишу что-то более длинное, например T-Shir
. Теперь я, вероятно, получу все три результата.
Большое спасибо
Omg Я сделал это работающим.
Для тех, кто с этим сталкивается - анализаторы определяются для каждого "поля" в связке. Другими словами, чтобы прикрепить анализатор к полю title
, наш shop/documents.py должен выглядеть следующим образом:
from elasticsearch_dsl import analyzer, tokenizer
autocomplete_analyzer = analyzer('autocomplete_analyzer',
tokenizer=tokenizer('trigram', 'nGram', min_gram=1, max_gram=20),
filter=['lowercase']
)from elasticsearch_dsl import analyzer, tokenizer
@registry.register_document
class CategoryDocument(Document):
#title: fields.TextField(analyzer=autocomplete_analyzer, search_analyzer='standard') # Here I'm trying to use the analyzer specified above <-- This was extremely incorrect, due to the colon in definition, I don't know how I missed it but I did...
title = fields.TextField(required=True, analyzer=autocomplete_analyzer) # This is it....
class Index:
name = 'categories'
settings = {
'number_of_shards': 1,
'number_of_replicas': 0,
'max_ngram_diff': 20 # This seems to be important due to the constraint for max_ngram_diff beeing 1
}
class Django:
model = Category
fields = [
# 'title' <-- Notice, I removed this field, it would be redeclaration error
# In reality here I have more fields
]
И он работает безупречно...