首页 |  我的博客 |  查看该博主内容分类 | 

django + elasticsearch + haystack构建全文搜索功能

材料准备

  1. es 主角包

  2. analysis-ik 插件,用于中文分词,下载后添加文件后缀.zip

  3. kibana (可选) 用于可视化查看es数据

注意:版本一定要相同

es

  • 安装
    将下载的包解压放到合适的位置(一般是/usr/local)
    tar -zxvf elasticsearch-7.13.4-linux-x86_64.tar.gz -C /usr/local/elasticsearch /usr/local/elasticsearch没有则创建
    修改为如下配置:
    /usr/local/elasticsearch/elasticsearch7.13.4/config/elasticsearch.yml

    ...
    -----------------------------Network-----------------------------
    # 添加
    discovery.type: single-node
    
    # 解决跨域问题
    # - 修改
    network.host: 0.0.0.0
    # - 添加
    http.cors.enabled: true
    http.cors.allow-origin: "*"
    # 开启安全验证(生产环境一般要设置)
    # xpack.security.enabled: true
    ...
    

    network.host原来就有,剩余三个新增就行

    • elasticsearch7.13.4/bin/elasticsearch为执行文件,在shell中执行即可启动(注意相对路径和绝对路径)
    • 生成用户密码
      • elasticsearch7.13.4/bin/elasticsearch-setup-passwords auto 自动生成
      • elasticsearch7.13.4/bin/elasticsearch-setup-passwords interactive 交互生成
        如果选择第一种自动生成,务必保存输出的密码内容,后续无法查看!
      • 修改elasticsearch密码(需旧密码)
        服务器发送http请求
      curl -u elastic -X POST 'localhost:9200/_security/user/elastic/_password' -H 'Content-Type: application/json' -d '{"password": "新密码"}'
      # 随后根据提示输入旧密码即可。
      
  • 创建用户
    es不能直接使用root启动,因此创建一个elastic用户
    useradd elastic
    更改文件归属

    chown -R elastic:elastic /usr/local/elasticsearch/elasticsearch-7.13.4
    
  • 启动
    /usr/bin/su - elastic -c '/usr/local/elasticsearch/elasticsearch7.13.4/bin/elasticsearch'
    /usr/bin/su - elastic 干净切换用户,-去除上个用户的环境
    -c切换用户后执行的命令

安装ik插件

将下载的文件解压到es文件夹/elasticsearch7.13.4/plugins中,为了方便,可将解压的ik文件夹命名为ik-7.13.4
重启es即可生效

  • 查看插件命令
    /usr/local/elasticsearch/elasticsearch7.13.4/bin/elasticsearch-plugin list

配置django

1. 安装模块

pip install elasticsearch==7.13.4
pip install drf-haystack

2. settings.py

INSTALLED_APPS = [
    "django.contrib.auth",
    "django.contrib.contenttypes",
    'haystack',
]

TEMPLATES = [
    "DIRS": [BASE_DIR / 'templates']  # es全文索引有用
]

HAYSTACK_CONNECTIONS = {
    'default': {
        # haystack操作es的核心模块(仅限7版本)
        'ENGINE': 'haystack.backends.elasticsearch7_backend.Elasticsearch7SearchEngine',
        # es服务端地址
        'URL': 'http://127.0.0.1:9200/',
        # es索引仓库
        'INDEX_NAME': 'haystack',   # 在ES生成的索引名称
 	   # 'KWARGS': {
 	   #	'http_auth': ('username', 'password'),  # 认证用户名和密码(如果设置了安全验证)
 	   #},
    }
}

# 当ORM操作数据库改变时,自动更新es的索引,否则es的索引会找不到新增的数据
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
# 用于同步删除es记录(信号删除未生效,原因暂时未知)
get_identifier = lambda obj: obj.id   # obj.id是你的记录主键
HAYSTACK_IDENTIFIER_METHOD = '项目名称.settings.get_identifier'

3. search_indexes.py (固定名称,务必放你的app根目录下)

class CommonUserIndex(indexes.SearchIndex, indexes.Indexable):
    # document=True 表示当前字段为全文索引
    # use_template=True 表示接下来haystack需要加载一个固定路径的html模板文件,让text与其他索引字段绑定映射关系
    text = indexes.CharField(document=True, use_template = True)  # 全文索引(可以根据配置,可以包括多个字段索引),省略了model_attr,参与templates名称构成,text名称可改
    # 普通索引(单字段,只能提供单个字段值的搜索,所以此处的声明更主要是为了提供给上面的text全文索引使用的)
    # es索引名 = indexes.索引数据类型(model_attr="ORM中的字段名")  注意如果字段返回的是json,要json。dumps转换成字符串
    username = indexes.IntegerField(model_attr="userinfo__username")
    nickname = indexes.CharField(model_attr="nickname")

    # 指定与当前es索引模型对接的mysql的ORM模型
    def get_model(self):
        return models.CommonUser

    # # 当用户搜索es索引的文档信息时,对应的提供给客户端的mysql数据行
    # def index_queryset(self, using=None):
    #     return self.get_model().objects.filter(is_delete=False, is_show=True )

4. 创建全文索引配置

api/templates/search/indexes/api/course_text.txt 目录构成必须是templates目录下的search/indexes/子应用目录名

course_text.txt名称构成:模型类名_全文索引变量.txt

{{ object.userinfo.username }}
{{ object.nickname }}

object表示当前orm的模型对应

5. 序列化器

旧序列化器可保留

class CommonUserHaystackSerializer(HaystackSerializer):
    class Meta:
        index_classes = [CommonUserIndex]
        fields = [
            'text',
            'username',
            'nickname'
        ]

    # def to_representation(self, instance):
    #     """在返回数据前可进行操作"""
    #     # self.context['request'].request.META['HTTP_HOST']  # 获取请求的来源ip
    #     instance.id += 1
    #     return super().to_representation(instance)

6. 视图类

旧视图类可保留

class CommonUserEsView(HaystackViewSet):
	"""全文搜索类"""
	index_models = [models.CommonUser]
	serializer_class = CommonUserHaystackSerializer
	# 如果不想用高亮关键字,将HaystackHighlightFilter换成HaystackFilter
	filter_backends = [DjangoFilterBackend, HaystackHighlightFilter]
	ordering_fields = ('username', 'nickname')
	pagination_class = MyPageNumberPagination

7. 路由

router.register('search', account.CommonUserEsView, basename='user-search')  # 没有queryset,要指定basename

8. 将mysql数据库数据同步到es

终端执行python manage.py rebuild_index

9. 使用

http://127.0.0.1:8000/api/search/?text=1
即:上面注册的路由加参数 + ?text=xxx

其他:

  • 相关命令

    python manage.py rebuild_index 重建索引 (--noinput忽略确认)

    python manage.py update_index --age=<num_hours> 更新索引,<num_hours>多久前的索引

    python manage.py clear_index 清除索引

    ... --noinput 不提示,直接操作

Tips:

  • 如果提示Decimal不能json,就float(...)转成浮点数
  • 数据类型还有问题,试试json.dumps()
posted @ 2023-02-20 16:43  Z哎呀  阅读(231)  评论(0)    收藏  举报