搜索引擎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})

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章