定制设计django+drf_haystack+elasticsearch+ik+高亮显示

0.前提准备

环境

  1. 1. 准备好django2.2
  2. 2. 创建一个app
  3. 3.elasticsearch7.5启动
  4. 4.定制设计可视化工具(实在没有,也没啥)

 models.py

  1. from django.db import models
  2. # Create your models here.
  3. class Article(models.Model):
  4. title = models.CharField(verbose_name='文章标题', max_length=225, db_index=True)
  5. content = models.TextField(verbose_name='内容')
  6. # 外键
  7. tag = models.ForeignKey(verbose_name='标签', to='Tag', on_delete=models.DO_NOTHING)
  8. def __str__(self):
  9. return self.title
  10. class Tag(models.Model):
  11. name = models.CharField(verbose_name='标签', max_length=225)
  12. def __str__(self):
  13. return self.name

1.安装

  1. pip3 install jieba  -i https://pypi.douban.com/simple/           
  2. pip3 install django-haystack -i https://pypi.douban.com/simple/
  3. pip3 install drf-haystack -i https://pypi.douban.com/simple/
  4. pip3 install elasticsearch==7.6.0 -i https://pypi.douban.com/simple/
  5. pip3 install django==2.2 -i https://pypi.douban.com/simple/

 2.setting.py

es定制设计其他版本配置

  1. # 注册
  2. INSTALLED_APPS = [
  3. ...
  4. 'haystack',
  5. 'rest_framework',
  6. ...
  7. ]
  8. # 配置7.x
  9. HAYSTACK_CONNECTIONS = {
  10. 'default': {
  11. 'ENGINE': 'haystack.backends.elasticsearch7_backend.Elasticsearch7SearchEngine',
  12. 'URL': 'http://127.0.0.1:9200/',
  13. 'INDEX_NAME': 'haystack',
  14. },
  15. }

3.配置 drf_haystack

3.1 目录介绍

文字介绍

app01/templates/search/indexes/app01/article_text.txt
indexes:定制设计是你要建立的索引的app,article定制设计是你要建立索引的那个模型名(小写)

图解

3.2 article.text.txt

定制设计给这几个字段建立索引,定制设计用作全文检索

  1. {{ object.tile}}
  2. {{ object.tag.name}}
  3. {{ object.content }}

4. search_indexes.py

4.1 介绍

search_indexes.py固定写法,定制设计必须叫这个名字

位置:在自己的app定制设计下创建即可

4.2 search_indexes.py

定制设计索引模型类的名称必须是 定制设计模型类名称 + Index

  1. from haystack import indexes
  2. from .models import Article
  3. # 必须继承 indexes.SearchIndex, indexes.Indexable
  4. # ArticleIndex定制设计是固定格式命名,Article是你models.py中的类名
  5. class ArticleIndex(indexes.SearchIndex, indexes.Indexable):
  6. # document=True:将为text定制设计字段内容建立索引,定制设计此字段内容,定制设计可以由多个字段内容联合而成,定制设计有且只有一个
  7. # use_template=True定制设计决定建立索引的字段内容,可以自定义模板
  8. text = indexes.CharField(document=True, use_template=True)
  9. # 下面的就是和你model里面的一样了
  10. # python manage.py rebuild_index
  11. # model_attr指定为对应模型的哪个字段
  12. # 以下字段作为辅助字段,我也不知道辅助什么
  13. id = indexes.IntegerField(model_attr='id')
  14. title = indexes.CharField(model_attr='title')
  15. tag = indexes.CharField(model_attr='tag')
  16. # 必须这个写,返回的就是你的model名称
  17. def get_model(self):
  18. """返回建立索引的模型类"""
  19. # 每次查询都走这个
  20. return Article
  21. # 返回你的查询的结果,可以改成一定的条件的,但是格式就是这样
  22. def index_queryset(self, using=None):
  23. """返回要建立索引的数据查询集"""
  24. # 写入es的数据
  25. query_set = self.get_model().objects.all()
  26. return query_set

5. serializers.py

  1. from haystack.utils import Highlighter
  2. from rest_framework import serializers
  3. from drf_haystack.serializers import HaystackSerializer, HighlighterMixin
  4. from .search_indexes import *
  5. class ArticleSerializer(serializers.ModelSerializer):
  6. """
  7. 序列化器
  8. """
  9. tag = serializers.CharField(source='tag.name')
  10. class Meta:
  11. model = Article
  12. # 返回除了搜索字段外的所需要的其他字段数据, 可以将所有需要返回的字段数据写上,便于提取
  13. fields = ('id', 'title', 'tag', 'content')
  14. # 写法一:普通序列化,使用内置的高亮
  15. class ArticleIndexSerializer(HaystackSerializer):
  16. """
  17. SKU索引结果数据序列化器
  18. """
  19. # 变量名称必须为 object 否则无法返回
  20. # 变量名称必须为 object 否则无法返回,
  21. # 返回除搜索字段以外的字段,由上面ArticleSerializer自定义返回字段
  22. object = ArticleSerializer(read_only=True) # 只读,不可以进行反序列化
  23. class Meta:
  24. index_classes = [ArticleIndex] # 索引类的名称,可以有多个
  25. # text 由索引类进行返回, object 由序列化类进行返回,第一个参数必须是text
  26. # 返回字段,不写默认全部返回
  27. # text字段必须有,不然无法实现搜索
  28. # 控制的是建立的索引字段
  29. fields = ['text', object]
  30. # fields = ['text']
  31. # 忽略字段
  32. # ignore_fields = ['title']
  33. # 除了该字段,其他的都返回,
  34. # exclude = ['title']
  35. '''
  36. # 写法二:自定义高亮,比内置的要慢一点
  37. class ArticleIndexSerializer(HighlighterMixin, HaystackSerializer):
  38. """
  39. SKU索引结果数据序列化器
  40. """
  41. # 变量名称必须为 object 否则无法返回,
  42. # 返回除搜索字段以外的字段,由上面ArticleSerializer自定义返回字段
  43. object = ArticleSerializer(read_only=True) # 只读,不可以进行反序列化
  44. # 高亮显示字段配置
  45. # highlighter_class = Highlighter
  46. # 前端自定义css名称
  47. highlighter_css_class = "my-highlighter-class"
  48. # html
  49. highlighter_html_tag = "em"
  50. # 最宽
  51. highlighter_max_length = 200
  52. class Meta:
  53. index_classes = [ArticleIndex] # 索引类的名称,可以有多个
  54. fields = ['text', object]
  55. '''

6. views.py

  1. from django.shortcuts import HttpResponse
  2. from drf_haystack.viewsets import HaystackViewSet
  3. from drf_haystack.filters import HaystackOrderingFilter, HaystackHighlightFilter
  4. from .models import *
  5. from .paginations import ArticleSearchPageNumberPagination
  6. from .serializers import ArticleIndexSerializer
  7. class ArticleSearchViewSet(HaystackViewSet):
  8. """
  9. 文章搜索
  10. """
  11. index_models = [Article] # 表模型,可以添加多个
  12. serializer_class = ArticleIndexSerializer
  13. pagination_class = ArticleSearchPageNumberPagination
  14. # 高亮,排序
  15. # HaystackOrderingFilter:排序,
  16. # HaystackHighlightFilter:内置高亮,如果使用了方式自定义高亮,就不要配置这个了
  17. filter_backends = [HaystackOrderingFilter, HaystackHighlightFilter]
  18. ordering_fields = ('id',)
  19. """ """
  20. # 重写,自己可以构造数据
  21. def list(self, request, *args, **kwargs):
  22. response = super(ArticleSearchViewSet, self).list(request, *args, **kwargs)
  23. data = response.data
  24. # 本文修改返回数据,把返回的索引字段去掉,您可以根据自己的需求,把这一句注释掉
  25. [item.pop('text') for item in data['results']]
  26. return response

7.urls.py

  1. from django.contrib import admin
  2. from django.urls import path, re_path
  3. from app01 import views
  4. # 路由方式一,首页即可看到数据
  5. # http://127.0.0.1:8000/search/?text=中国&ordering=id
  6. # http://127.0.0.1:8000/search/?text=中国
  7. from rest_framework.routers import SimpleRouter
  8. router = SimpleRouter()
  9. router.register('search', views.ArticleSearchViewSet, basename='search_api')
  10. # router.register("", views.ArticleAPIView)
  11. urlpatterns = [
  12. # re_path(r'^$', views.ArticleSearchViewSet.as_view({'get': 'list'})),
  13. path('admin/', admin.site.urls),
  14. path('update/', views.update)
  15. ]
  16. urlpatterns += router.urls
  17. # 路由方式二,大黄页
  18. """
  19. # http://127.0.0.1:8000/search/?text=中国&ordering=id
  20. # http://127.0.0.1:8000/search/?text=中国
  21. urlpatterns = [
  22. path('admin/', admin.site.urls),
  23. re_path(r'search_one/(?P<pk>\d+)/', views.ArticleSearchViewSet.as_view({'get': 'retrieve'})),
  24. path('search/', views.ArticleSearchViewSet.as_view({'get': 'list'})),
  25. ]
  26. """

8.paginations

  1. from rest_framework.pagination import PageNumberPagination
  2. class ArticleSearchPageNumberPagination(PageNumberPagination):
  3. """文章搜索分页器"""
  4. # 每页显示几条
  5. page_size = 10
  6. # 最大数量
  7. max_page_size = 5000
  8. # 前端自定义查询的数量,?size=10
  9. page_size_query_param = "size"
  10. # 查询参数
  11. page_query_param = "page"

9.执行

  1. python manage.py makemigrations
  2. python manage.py migrate
  3. # 重新创建索引,删掉之前的,进行数据同步
  4. python manage.py rebuild_index

10. 验证是从es中查询的数据

1.直接修改mysql数据库数据,查看查询的数据会不会改变,不改就是es,改了就是mysql

11.换成ik分词器

11.1安装

11.2 使用ik重写es7.5引擎

10.2.1 新建elasticsearch_ik_backend.py(在自己的app下)

在 blog应用下新建名为 elasticsearch7_ik_backend.py 的文件,

继承 Elasticsearch7SearchBackend(后端) 和 Elasticsearch7SearchEngine(搜索引擎) 并重写建立索引时的分词器设置

elasticsearch7_ik_backend.py

  1. from haystack.backends.elasticsearch7_backend import Elasticsearch7SearchBackend, Elasticsearch7SearchEngine
  2. """
  3. 分析器主要有两种情况会被使用:
  4. 第一种是插入文档时,将text类型的字段做分词然后插入倒排索引,
  5. 第二种就是在查询时,先对要查询的text类型的输入做分词,再去倒排索引搜索
  6. 如果想要让 索引 和 查询 时使用不同的分词器,ElasticSearch也是能支持的,只需要在字段上加上search_analyzer参数
  7. 在索引时,只会去看字段有没有定义analyzer,有定义的话就用定义的,没定义就用ES预设的
  8. 在查询时,会先去看字段有没有定义search_analyzer,如果没有定义,就去看有没有analyzer,再没有定义,才会去使用ES预设的
  9. """
  10. DEFAULT_FIELD_MAPPING = {
  11. "type": "text",
  12. "analyzer": "ik_max_word",
  13. # "analyzer": "ik_smart",
  14. "search_analyzer": "ik_smart"
  15. }
  16. class Elasticsearc7IkSearchBackend(Elasticsearch7SearchBackend):
  17. def __init__(self, *args, **kwargs):
  18. self.DEFAULT_SETTINGS['settings']['analysis']['analyzer']['ik_analyzer'] = {
  19. "type": "custom",
  20. "tokenizer": "ik_max_word",
  21. # "tokenizer": "ik_smart",
  22. }
  23. super(Elasticsearc7IkSearchBackend, self).__init__(*args, **kwargs)
  24. class Elasticsearch7IkSearchEngine(Elasticsearch7SearchEngine):
  25. backend = Elasticsearc7IkSearchBackend

11.3 修改settings.py(切换成功)

  1. # es 7.x配置
  2. HAYSTACK_CONNECTIONS = {
  3. 'default': {
  4. # 'ENGINE': 'haystack.backends.elasticsearch7_backend.Elasticsearch7SearchEngine',
  5. 'ENGINE': 'app01.elasticsearch_ik_backend.Elasticsearch7IkSearchEngine',
  6. 'URL': 'http://127.0.0.1:9200/',
  7. # elasticsearch建立的索引库的名称,一般使用项目名作为索引库
  8. 'INDEX_NAME': 'ha_drf',
  9. },
  10. }

11.4 重建索引,同步数据

python manage.py rebuild_index

11.5 补充

11.5.1 未成功切换成ik

haystack 原先加载的是 ...\venv\Lib\site-packages\haystack\backends 文件夹下的 elasticsearch7_backend.py 文件,打开即可看到 elasticsearch7 引擎的默认配置 

若用上述方法建立出来的索引字段仍使用 snowball 分词器,则将原先elasticsearch7_backend.py 文件中的 DEFAULT_FIELD_MAPPING 也修改为 ik 分词器(或许是因为版本问题)

位置:D:\py_virtualenv\dj_ha\Lib\site-packages\haystack\backends\elasticsearch7_backend.py

修改内容:

  1. DEFAULT_FIELD_MAPPING = {
  2. "type": "text",
  3. "analyzer": "ik_max_word",
  4. "search_analyzer": "ik_smart",
  5. }

11.5.2 es6版本加入ik,重写引擎

  1. from haystack.backends.elasticsearch_backend import ElasticsearchSearchBackend
  2. from haystack.backends.elasticsearch_backend import ElasticsearchSearchEngine
  3. class IKSearchBackend(ElasticsearchSearchBackend):
  4. DEFAULT_ANALYZER = "ik_max_word" # 这里将 es 的 默认 analyzer 设置为 ik_max_word
  5. def __init__(self, connection_alias, **connection_options):
  6. super().__init__(connection_alias, **connection_options)
  7. def build_schema(self, fields):
  8. content_field_name, mapping = super(IKSearchBackend, self).build_schema(fields)
  9. for field_name, field_class in fields.items():
  10. field_mapping = mapping[field_class.index_fieldname]
  11. if field_mapping["type"] == "string" and field_class.indexed:
  12. if not hasattr(
  13. field_class, "facet_for"
  14. ) and not field_class.field_type in ("ngram", "edge_ngram"):
  15. field_mapping["analyzer"] = getattr(
  16. field_class, "analyzer", self.DEFAULT_ANALYZER
  17. )
  18. mapping.update({field_class.index_fieldname: field_mapping})
  19. return content_field_name, mapping
  20. class IKSearchEngine(ElasticsearchSearchEngine):
  21. backend = IKSearchBackend

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发