django-elasticsearch-dsl-drf 搜索服务搭建教学
一、整体架构
本搜索服务基于 Django + django-elasticsearch-dsl + django-elasticsearch-dsl-drf 搭建,实现MySQL业务数据与Elasticsearch搜索引擎的联动,提供标准化、可分页、可筛选、可排序的全文搜索API服务。
整体架构流转逻辑:Django模型数据 → ES文档映射 → DRF视图接口 → 前端搜索请求
架构组成说明:
-
Django Model(SKU):业务数据源,存储商品SKU基础数据
-
django-elasticsearch-dsl:实现Django与ES的数据映射、索引定义、数据自动同步
-
django-elasticsearch-dsl-drf:基于DRF封装ES查询能力,提供搜索、过滤、排序、分页接口
-
Elasticsearch 7.17.x:底层搜索引擎,通过倒排索引实现高效全文检索
-
documents.py:定义ES索引结构、字段映射、数据过滤规则
-
DocumentViewSet:核心视图类,搭配各类过滤器实现搜索功能
二、环境依赖安装
搭建前需安装指定版本依赖包,适配ES7.x版本,保证框架兼容性。
Plain
pip install django-elasticsearch-dsl==7.3
pip install django-elasticsearch-dsl-drf
三、项目配置(settings.py)
在项目配置文件中注册ES相关应用,并配置Elasticsearch服务连接地址。
Plain
# settings/dev.py
INSTALLED_APPS = [
# 原有项目应用
'django_elasticsearch_dsl', # ES DSL核心集成
'django_elasticsearch_dsl_drf', # ES DSL DRF接口集成
]
# Elasticsearch连接配置
ELASTICSEARCH_DSL = {
'default': {
'hosts': 'http://192.168.36.129:9200', # ES服务地址
},
}
四、定义ES文档(documents.py)
该文件用于绑定Django模型、定义ES索引名称、字段结构、索引配置,同时实现数据过滤和自动同步能力。通过装饰器完成自动注册,无需手动编写信号,即可实现MySQL数据增删改自动同步ES。
Plain
# apps/goods/documents.py
from django_elasticsearch_dsl import Document, fields
from django_elasticsearch_dsl.registries import registry
from .models import SKU
@registry.register_document
class SKUDocument(Document):
"""商品SKU搜索文档"""
# 自定义关联字段
id = fields.IntegerField(attr='id')
category_name = fields.TextField(attr='category.name')
class Index:
# ES索引名称
name = 'meiduo_dsl'
# 索引分片配置
settings = {
'number_of_shards': 1,
'number_of_replicas': 0,
}
class Django:
# 绑定Django业务模型
model = SKU
# 自动映射的模型基础字段
fields = [
'name',
'caption',
'price',
'sales',
'stock',
'is_launched',
]
@classmethod
def get_queryset(cls):
"""只索引上架商品,过滤无效数据"""
return SKU.objects.filter(is_launched=True)
五、创建ES数据序列化器(serializers.py)
用于序列化ES查询到的文档数据,统一接口返回格式,指定需要对外暴露的字段。
Plain
# apps/goods/serializers.py
from django_elasticsearch_dsl_drf.serializers import DocumentSerializer
from .documents import SKUDocument
class SKUDocumentSerializer(DocumentSerializer):
"""ES文档序列化器"""
class Meta:
document = SKUDocument
# 接口返回字段
fields = [
'id',
'name',
'caption',
'price',
'sales',
'stock',
'category_name',
'is_launched',
]
六、编写搜索视图(views.py)
基于框架提供的DocumentViewSet实现接口能力,配置分页、搜索、过滤、排序后端,实现完整的商品搜索功能。
Plain
# apps/goods/views.py
from rest_framework.pagination import PageNumberPagination
from django_elasticsearch_dsl_drf.viewsets import DocumentViewSet
from django_elasticsearch_dsl_drf.filter_backends import (
FilteringFilterBackend,
OrderingFilterBackend,
SearchFilterBackend,
DefaultOrderingFilterBackend,
)
from .documents import SKUDocument
from .serializers import SKUDocumentSerializer
# 自定义分页类
class StandardResultsSetPagination(PageNumberPagination):
"""标准分页配置"""
page_size = 10
page_size_query_param = 'page_size'
max_page_size = 100
class SKUDocumentViewSet(DocumentViewSet):
"""SKU商品搜索接口视图"""
document = SKUDocument
serializer_class = SKUDocumentSerializer
pagination_class = StandardResultsSetPagination
# 启用的过滤器后端
filter_backends = [
SearchFilterBackend, # 全文关键词搜索
FilteringFilterBackend, # 精确条件过滤
OrderingFilterBackend, # 自定义排序
DefaultOrderingFilterBackend, # 默认排序兜底
]
# 全文搜索匹配字段
search_fields = (
'name',
'caption',
)
# 精确过滤字段映射
filter_fields = {
'is_launched': 'is_launched',
}
# 支持排序的字段
ordering_fields = {
'price': 'price',
'sales': 'sales',
}
# 默认排序规则:销量降序
ordering = ('-sales',)
七、配置路由(urls.py)
通过DRF路由注册视图,生成标准化的搜索接口地址。
Plain
# apps/goods/urls.py
from rest_framework.routers import DefaultRouter
from .views import SKUDocumentViewSet
router = DefaultRouter()
# 注册搜索接口路由
router.register('skus/dsl_search', SKUDocumentViewSet, basename='skus_dsl_search')
urlpatterns = router.urls
八、索引创建与数据导入命令
项目配置完成后,需执行命令创建ES索引、导入存量业务数据,接口才可正常使用。
Plain
# 进入项目根目录
cd d:\Git01\git-code\meiduo-test01\meiduo_mall
# 1. 创建ES索引结构
python manage.py search_index --create
# 2. 导入模型数据至ES索引
python manage.py search_index --populate
# 3. 重建索引(修改文档字段、索引配置后使用)
python manage.py search_index --rebuild
# 4. 删除索引
python manage.py search_index --delete
九、项目文件结构
Plain
meiduo_mall/
├── meiduo_mall/
│ ├── apps/
│ │ └── goods/
│ │ ├── documents.py # ES索引文档定义
│ │ ├── serializers.py # ES数据序列化器
│ │ ├── views.py # 搜索接口视图
│ │ └── urls.py # 接口路由配置
│ └── settings/
│ └── dev.py # 项目配置文件(ES配置)
└── requirements.txt # 项目依赖文件
十、接口查询参数使用说明
1. 全文搜索
通过search参数匹配商品名称、简介关键词
2. 精确过滤
通过is_launched参数过滤上架/下架商品
3. 排序查询
通过ordering参数实现升降序排序
-
价格升序:/skus/dsl_search/?ordering=price
-
价格降序:/skus/dsl_search/?ordering=-price
-
销量降序:/skus/dsl_search/?ordering=-sales
4. 分页查询
通过page、page_size控制分页
- /skus/dsl_search/?page=1&page_size=10
5. 组合查询
支持搜索、排序、分页多参数组合使用
- /skus/dsl_search/?search=华为&ordering=-price&page=1&page_size=5
十一、接口响应格式
接口返回标准化分页JSON数据,包含总数量、上下页地址、结果列表。
Plain
{
"count": 8,
"next": "http://127.0.0.1:8000/skus/dsl_search/?page=2&search=华",
"previous": null,
"results": [
{
"id": 9,
"name": "华为 HUAWEI P10 Plus...",
"caption": "wifi双天线设计!...",
"price": 3388.0,
"sales": 21,
"stock": 6,
"category_name": "手机",
"is_launched": true
}
]
}
十二、核心组件功能说明
| 组件 | 核心作用 |
|---|---|
| Document | 定义ES索引结构、字段映射、索引配置,绑定Django模型 |
| DocumentSerializer | 序列化ES文档数据,统一接口返回字段与格式 |
| DocumentViewSet | 核心视图,整合所有查询能力,提供搜索API接口 |
| SearchFilterBackend | 实现全文关键词搜索功能 |
| FilteringFilterBackend | 实现字段精确过滤功能 |
| OrderingFilterBackend | 实现自定义字段排序功能 |
| DefaultOrderingFilterBackend | 配置接口默认排序规则 |
十三、数据自动同步机制
通过 @registry.register_document 装饰器自动完成数据同步,无需手动编写信号处理器:
-
Django中执行 SKU.save()(新增/修改数据)→ ES索引自动更新对应文档
-
Django中执行 SKU.delete()(删除数据)→ ES索引自动删除对应文档
优势:零代码实现MySQL与Elasticsearch数据实时同步,降低开发成本。
十四、技术对比:Haystack vs dsl-drf
| 对比项 | Haystack | dsl-drf |
|---|---|---|
| 索引定义方式 | search_indexes.py + 模板文件 | 纯 documents.py 配置,更简洁 |
| 数据同步 | 需手动配置信号处理器 | 装饰器自动同步,无需手动配置 |
| 查询方式 | HaystackViewSet | DocumentViewSet,贴合DRF规范 |
| 过滤/排序能力 | 功能有限 | 功能强大、配置灵活 |
| ES版本适配 | 需自定义适配 | 原生适配ES7.x版本 |
| 代码量 | 冗余代码较多 | 精简高效 |
十五、搭建流程总结
-
安装依赖:安装dsl核心包与drf适配包
-
项目配置:注册应用,配置ES服务连接地址
-
定义索引:编写documents.py,绑定模型、定义索引结构与数据规则
-
编写序列化器:规范ES数据返回格式
-
编写视图:配置分页、搜索、过滤、排序后端,实现接口能力
-
配置路由:注册视图路由,生成可访问接口
-
初始化数据:执行命令创建索引、导入存量数据,完成服务搭建
后续会整理ES数据库相关知识