Поиск в Django REST Framework с помощью Elasticsearch

от автора

Пользователи ищут товары в интернет-магазине, ищут стати, поиск это неотъемлемый компонент сайта. Быстрый и гибкий поиск сложно реализовать средствами реляционных баз данных. Для таких задач используют поисковые движки, один из которых Elasticsearch. Elasticsearch хорошо документирован и доступен из коробки на AWS.

Для работы с elasticsearch используется библиотека elasticsearch-py или elasticsearch-dsl-py. elasticsearch-dsl-py это надстройка над elasticsearch-py, она проста в использовании и поддерживает elasticsearch версии 5.x. На базе этой библиотеки была создана библиотека django-rest-elasticsearch, которая основана на идеологии существующего поиска в Django REST Framework. Ниже я детально распишу как реализовать поиск в Django REST Framework с помощью elasticsearch используя данную библиотеку.

В качестве примера рассмотрим реализацию простого блога с фильтрацией по тегам и поиском по заголовку статей.

Установка

Процесс установки elasticsearch и django детально расписан в официальных документациях. С установкой пакета все достаточно просто

pip install django-rest-elasticsearch

Создание модели и индекса

Создадим модель

class Blog(models.Model):     title = models.CharField(_('Title'), max_length=1000)     created_at = models.DateTimeField(_('Created at'), auto_now_add=True)     body = models.TextField(_('Body'))     tags = ArrayField(models.CharField(max_length=200), blank=True, null=True)     is_published = models.BooleanField(_('Is published'), default=False)      def __str__(self):         return self.title

После создания модели опишем нашу модель в виде elasticsearch документа.

class BlogIndex(DocType):      pk = Integer()     title = Text(fields={'raw': Keyword()})     created_at = Date()     body = Text()     tags = Keyword(multi=True)     is_published = Boolean()      class Meta:         index = 'blog'

Теперь можно создать индекс в elasticsearch

BlogIndex.init()

Автоматическое обновление документов в elasticsearch

После создания модели и индекса, нужно что бы любые изменения в нашей модели были отображены в elasticsearch. Наилучшим средством это сделать добавить django сигнал, который отправить уведомления когда будут происходит изменения в модели. Прежде чем создать сигнал создадим сериалайзер для преобразования django объекта в документ elasticsearch

from rest_framework_elasticsearch.es_serializer import ElasticModelSerializer from .models import Blog from .search_indexes import BlogIndex  class ElasticBlogSerializer(ElasticModelSerializer):     class Meta:         model = Blog         es_model = BlogIndex         fields = ('pk', 'title', 'created_at', 'tags', 'body', 'is_published')

Теперь добавим сигнал

from django.db.models.signals import pre_save, post_delete from django.dispatch import receiver from .serializers import Blog, ElasticBlogSerializer  @receiver(pre_save, sender=Blog, dispatch_uid="update_record") def update_es_record(sender, instance, **kwargs):     obj = ElasticBlogSerializer(instance)     obj.save()  @receiver(post_delete, sender=Blog, dispatch_uid="delete_record") def delete_es_record(sender, instance, *args, **kwargs):     obj = ElasticBlogSerializer(instance)     obj.delete(ignore=404)

После добавления сигнала, любые изменения в модели моментально будут сделаны в elasticsearch

Создание view

Приступим к создания view для поиска и фильтрации

from elasticsearch import Elasticsearch, RequestsHttpConnection from rest_framework_elasticsearch import es_views, es_filters from .search_indexes import BlogIndex  class BlogView(es_views.ListElasticAPIView):     es_client = Elasticsearch(hosts=['elasticsearch:9200/'],                               connection_class=RequestsHttpConnection)     es_model = BlogIndex     es_filter_backends = (         es_filters.ElasticFieldsFilter,         es_filters.ElasticSearchFilter     )     es_filter_fields = (         es_filters.ESFieldFilter('tag', 'tags'),     )     es_search_fields = (         'tags',         'title',     )

Вот и все, примеры поиска

http://example.com/blogs/api/list?search=elasticsearch http://example.com/blogs/api/list?tag=opensource http://example.com/blogs/api/list?tag=opensource,aws

Полный код примера доступен на github. Надеюсь что статья поможет Вам реализовать поиск в Вашем проекте. 

ссылка на оригинал статьи https://habrahabr.ru/post/327694/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *