Django ORM 的 icontains 不适合全文搜索,因其基于 SQL LIKE 无法处理词干、同义词、相关性及中文分词;应使用 django-elasticsearch-dsl 同步数据至 Elasticsearch,并配置 ES_URL、Document 映射、IK 分词器,通过 Search 类链式查询并设置字段权重与高亮。

为什么直接用 Django ORM 的 icontains 不适合全文搜索
因为 icontains 本质是 SQL 的 LIKE '%keyword%',不支持词干提取、同义词、相关性排序,更无法处理中文分词——搜索“跑步鞋”几乎匹配不到“跑鞋”或“运动鞋”。Elasticsearch 是专为这类需求设计的,但直接裸调用 REST API 容易出错,也不利于 Django 模型联动。
用 django-elasticsearch-dsl 同步模型数据到 ES
这个库能自动将 Django 模型字段映射为 ES 的 text 或 keyword 类型,并监听 post_save 和 post_delete 信号实时更新索引。关键不是装上就完事,而是要注意三处配置:
-
ES_URL必须在settings.py中显式声明,比如'http://127.0.0.1:9200',不能依赖环境变量未设时的默认值 - 模型类需继承
Document,并在class Index里指定name(如'product')和settings(尤其'number_of_shards'建议设为 1,开发环境避免分片开销) - 中文搜索必须配
analyzer:在Index类中加'analyzer': 'ik_max_word',并确保 Elasticsearch 已安装ik分词插件,否则搜“笔记本电脑”会拆成单字
查询时绕过 raw REST 调用,用 Search 类构造 DSL
别写 requests.post(...) 拼 JSON 查询体——既难调试又难复用。直接用 Search 实例链式调用更安全:
from django_elasticsearch_dsl.registries import registry
from elasticsearch_dsl import Search
s = Search(index='product').query('multi_match', query='无线耳机', fields=['name^3', 'description'])
results = s.execute()
注意点:
立即学习“Python免费学习笔记(深入)”;
-
fields列表里用^3表示字段权重,name匹配得分比description高 3 倍 - 如果结果为空但确定数据存在,先检查
registry.get_documents()是否包含目标模型——没被@register装饰的模型不会进索引 - 生产环境务必加
highlight:用s.highlight('name', 'description')获取高亮片段,前端渲染时就能标出关键词位置
部署前必须验证的两个断点
本地跑通不等于上线能用。最容易卡住的是:
- ES 连接超时:Django 启动时会尝试连接 ES 并同步 mapping,若
ES_URL不可达,整个项目起不来。建议在management command里单独做连接探测,而不是塞在ready()里硬等 - 索引未 refresh:新写入的文档默认 1 秒后才可查(ES 的 near real-time 特性),测试时用
.params(refresh=True)强制刷新,但线上禁用——它会拖慢写入性能
中文分词、字段权重、索引刷新时机,这三个点任何一个没对齐,搜索就会“看起来有结果,但总不对”。


















