Пользователи ищут товары в интернет-магазине, ищут стати, поиск это неотъемлемый компонент сайта. Быстрый и гибкий поиск сложно реализовать средствами реляционных баз данных. Для таких задач используют поисковые движки, один из которых 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/
Добавить комментарий