搜索引擎elasticsearch,对接Django

提高Django的搜索性能

elasticsearch部署在docker中

至于elasticsearch的基础知识,就不多说,有丰富的文档,供君阅读。

建立索引数据模型

这里使用的是python中的elasticsearch_dsl,比较友好。使用ik中文分词插件,来进行分词,中文搜索。数据模型,与django中的model相对应,这里只选用用于搜索的关键字,存入索引库。

class AuthorComment(InnerDoc):
    id = Text()
    name = Text()
  
class Course(Document):
    id = Text()
    name = Text(analyzer="ik_smart", search_analyzer="ik_smart", fields={'name': Keyword()})

    class Index:
        name = 'course'
        settings = {
            "number_of_shards": 2,
        }

Django数据发生变化时,同步到elasticsearch

这里利用Django提供的信号机制实现同步,如果有其他需要,可以自己写相应的信号来处理。

@receiver(post_save, sender=ModelCourse)
def post_save_course(sender, **kwargs):
    try:
        instance = kwargs.get('instance')
        created = kwargs.get('created')
        para = {
            'name': instance.name,
            'img': instance.img,
        }
        if not created:
            course = Course.get(id=instance.id)
            course.update(**para)
        else:
            para['id'] = instance.id
            para['meta'] = {'id': instance.id}
            course = Course(**para)
            course.save()
    except BaseException as e:
        logger.error(e)
        logger.error('{} 添加一对一索引失败'.format(kwargs))

建立搜索模型

这里仅仅使用name字段搜索

class CourseSearch(FacetedSearch):
    index = 'course'
    doc_types = Course
    fields = ['name', ]

    def search(self):
        s = super(CourseSearch, self).search()
        return s.filter('term', strike=False)

建立序列化器

class CourseSerializer(serializers.Serializer):
    id = serializers.CharField(read_only=True)
    name = serializers.CharField(read_only=True)

    class Meta:
        fields = '__all__'

建立视图

这里的分页模型,均是从Django rest frame库中摘抄,见谅,见谅

from rest_framework.response import Response
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.settings import api_settings

from .search import CourseSearch
from .serializers import CourseSerializer


class SearchViewSet(viewsets.ViewSet):
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

    @property
    def paginator(self):
        """
        The paginator instance associated with the view, or `None`.
        """
        if not hasattr(self, '_paginator'):
            if self.pagination_class is None:
                self._paginator = None
            else:
                self._paginator = self.pagination_class()
        return self._paginator

    def paginate_queryset(self, queryset):
        """
        Return a single page of results, or `None` if pagination is disabled.
        """
        if self.paginator is None:
            return None
        return self.paginator.paginate_queryset(queryset, self.request, view=self)

    def get_paginated_response(self, data):
        """
        Return a paginated style `Response` object for the given output data.
        """
        assert self.paginator is not None
        return self.paginator.get_paginated_response(data)

    @staticmethod
    def get_result(data):
        data = data['_source']
        try:
            author = data['author']
            data['author'] = author[0]
        except KeyError:
            pass
        return data
       
    @action(methods=['get'], detail=False)
    def course(self, request):
        name = self.request.query_params.get('name', None)
        bs = CourseSearch(name)
        response = bs.execute()
        data = response.hits.hits[0:100]
        data = list(map(self.get_result, data))
        page = self.paginate_queryset(data)
        serializer = CourseSerializer(page, many=True)
        data = self.get_paginated_response(serializer.data)
        return Response({'message': '获取成功', 'status': status.HTTP_200_OK, 'data': data})

你可能感兴趣的:(Python,elasticsearch,Django)