Users search for products in the online store, search for articles, search is an integral component of the site. Fast and flexible search is difficult to implement with relational databases. For such tasks use search engines, one of which is Elasticsearch . Elasticsearch is well documented and available out of the box on AWS.
To work with elasticsearch, the library uses elasticsearch-py or elasticsearch-dsl-py . elasticsearch-dsl-py is an add-on over elasticsearch-py, it is easy to use and supports version 5.x elasticsearch. Based on this library, the django-rest-elasticsearch library was created, which is based on the ideology of the existing search in the Django REST Framework . Below I will describe in detail how to implement a search in the Django REST Framework using elasticsearch using this library.
As an example, consider the implementation of a simple blog with filtering by tags and search by article title.
The installation process of elasticsearch and django is detailed in the official documentation. With the installation package everything is quite simple
pip install django-rest-elasticsearch
Create a model
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
After creating the model, we will describe our model as an elasticsearch document.
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'
Now you can create an index in elasticsearch
BlogIndex.init()
After creating the model and the index, it is necessary that any changes in our model are displayed in elasticsearch. The best way to do this is to add a django signal that will send notifications when changes occur in the model. Before creating a signal, create a serializer for converting a django object into an elasticsearch document
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')
Now add a signal
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)
After adding a signal, any changes in the model will be instantly made in elasticsearch
Let's start creating a view for searching and filtering.
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', )
That's all, search examples
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
The full sample code is available on github . I hope that the article will help you implement the search in your project.
Source: https://habr.com/ru/post/327694/
All Articles