Django_elasticsearch_dsl_drf не возвращает ожидаемый результат - PullRequest
0 голосов
/ 18 апреля 2020

Я применял elasti c поиск в одном моем django приложении, ниже приведены мои фрагменты кода

documents.py

ads_index = Index("ads_index")
ads_index.settings(
    number_of_shards=1,
    number_of_replicas=0
)

html_strip = analyzer(
    'html_strip',
    tokenizer="standard",
    filter=["standard", "lowercase", "stop", "snowball"],
    char_filter=["html_strip"]
)


@ads_index.doc_type
class AdDocument(Document):
    id = fields.IntegerField(attr='id')

    title = fields.TextField(
    analyzer=html_strip,
    fields={
        'title': fields.TextField(analyzer='keyword'),
    }
   )

   description = fields.TextField(
    analyzer=html_strip,
    fields={
        'description': fields.TextField(analyzer='keyword'),
    }
   )

   category = fields.ObjectField(
    properties={
        'title': fields.TextField(),
    }
)

class Django:
    model = Ad  # The model associated with this Document

    # The fields of the model you want to be indexed in Elasticsearch
    fields = [
        'price',
        'created_at',
    ]

    related_models = [Category]

def get_queryset(self):
    return super().get_queryset().select_related('category')

def get_instances_from_related(self, related_instance):
    if isinstance(related_instance, Category):
        return related_instance.ad_set.all()

сериализатор

class AdDocumentSerializer(DocumentSerializer):
    class Meta:
        document = AdDocument
        fields = (
            "id",
            "title",
            "description",
            "price",
            "created_at",
        )

viewset

class AdViewSet(DocumentViewSet):
    document = AdDocument
    serializer_class = AdDocumentSerializer
    ordering = ('id',)
    lookup_field = 'id'

    filter_backends = [
        DefaultOrderingFilterBackend,
        FilteringFilterBackend,
        CompoundSearchFilterBackend,
        SuggesterFilterBackend,
    ]

    search_fields = (
        'title',
        'description',
    )

    filter_fields = {
        'id': {
            'field': 'id',
            'lookups': [
                LOOKUP_FILTER_RANGE,
                LOOKUP_QUERY_IN,
                LOOKUP_QUERY_GT,
                LOOKUP_QUERY_GTE,
                LOOKUP_QUERY_LT,
                LOOKUP_QUERY_LTE,
            ],
        },
        'title': 'title.raw',
        'description': 'description.raw',
    }

    ordering_fields = {
        'id': 'id',
    }

Ниже приведены мои данные, которые у меня есть

data

Когда я нажимаю http://127.0.0.1:8000/ads/search/?search=Tit, он ничего не возвращает, кроме когда я нажимаю http://127.0.0.1:8000/ads/search/?search=a, это дает мне один результат.

Что здесь с моим кодом? Любая помощь будет оценена: -)

1 Ответ

1 голос
/ 18 апреля 2020

С помощью анализатора keyword вся входная строка указывается в инвертированном индексе, так что вы можете искать только по точному совпадению . Я использую библиотекуasticsearch в python, и я не очень хорошо знаюasticsearch-dsl. Я постараюсь ответить вам, используя чистую конфигурацию elasti c, а затем вам нужно поискать, как реализовать этот conf с библиотекой elasticsearch-dsl в python. Если вы также ищете частичную строку внутри некоторых слов, вы должны указать их с помощью edge-ngram token filter - do c здесь . С помощью этого метода вы также можете выполнить автозаполнение в строке поиска, потому что частичная строка в начале слова доступна для поиска. Вы должны реализовать спецификацию c search_analyzer, потому что вы хотите, чтобы строка входного запроса не была токенизирована с помощью фильтра токенов edge-ngram - для объяснения посмотрите здесь *1010* и здесь

{
    "settings": {
        "number_of_shards": 1, 
        "analysis": {
            "filter": {
                "autocomplete_filter": { 
                    "type":     "edge_ngram",
                    "min_gram": 1,
                    "max_gram": 20
                }
            },
            "analyzer": {
                "autocomplete": {
                    "type":      "custom",
                    "tokenizer": "standard",
                    "filter": [
                        "lowercase",
                        "autocomplete_filter" 
                    ]
                }
            }
        }
    },
      "mappings": {
        "properties": {
          "title": {
            "type": "text",
            "analyzer" : "autocomplete",
            "search_analyzer" : "standard"
          },
          "description": {
            "type": "text",
            "analyzer" : "autocomplete",
            "search_analyzer" : "standard"
          }
        }
      }
    }

Если вам не нравится это решение, потому что вы также будете искать частичную строку в середине слова - например, запросить itl для получения title строки, вам следует внедрить новый ngram-tokenizer с нуля - сделать c здесь :

{
  "settings": {
    "analysis": {
      "analyzer": {
        "autocomplete": {
          "tokenizer": "my_tokenizer",
          "filter": ["lowercase"]
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "ngram",
          "min_gram": 1,
          "max_gram": 20,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      }
    }
  },
      "mappings": {
        "properties": {
          "title": {
            "type": "text",
            "analyzer" : "autocomplete",
            "search_analyzer" : "standard"
          },
          "description": {
            "type": "text",
            "analyzer" : "autocomplete",
            "search_analyzer" : "standard"
          }
        }
      }
    } 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...