django使用haystack调用Elasticsearch实现索引搜索


Posted in Python onJuly 24, 2019

前言:

在做一个商城项目的时候,需要实现商品搜索功能。

说到搜索,第一时间想到的是数据库的 select * from tb_sku where name like %苹果手机%

或者django的 SKU.objects.filter(name__contains="苹果手机")

但是,假如你的数据库有几千万条数据,name字段没有索引,可能查询需要十几分钟,用户可能会等你?那为什么不给name字段增加索引?商品表不仅仅是用来查询,也会经常修改数据,新增删除数据等。建立索引后,做增删改操作时也会大大占用数据库资源。所以应该怎么解决呢?

Elasticsearch!

一个强大的基于Lucene的全文搜索服务器!维基百科、Stack Overflow、Github都在用。

如果想详细了解其原理的话,可以参考:Elasticsearch 基础介绍及索引原理分析

这里只是简单说一下他的原理。

Elasticsearch原理:

django使用haystack调用Elasticsearch实现索引搜索

部署好ElasticSearch服务器后,刚开始需要创建索引,ES索引库会对数据库中的数据进行一遍预处理,单独建立起一份索引结构数据。

理解:

假如你的商品表里有这几个字段。id,名字,副标题,价格,商品图片链接地址,评论数,是否上架。

一般用户会根据名字或者副标题来搜索。此时名字、副标题这个字段就需要建立索引(当然,id也要,人家在mysql那里是主键总要给点面子吧)。但是后端返回给前端的数据,不仅仅是需要名字、副标题啊。你还要价格什么的呢!所以我们还要指定需要的字段,不然直接找个名字或者副标题出来有什么用?

所以刚开始创建索引库时,ElasticSearch服务端会根据我们指定要作为索引的字段(名字、副标题、id)、要返回的字段(价格...),同步一份到ES索引库里面。为什么要同步到elasticsearch?因为查找快呀。至于为什么ElasticSearch查找这么快,可以参考一下上面链接的原理。

注意上面的图,ElasticSearch是C/S架构的软件。下面说一下,服务端怎么搭建?

ElasticSearch服务端的搭建:

在搭建前说下,ElasticSearch建立索引时会分词。什么是分词呢?例如“我今天吃了一个汉堡包”。分词后是“我”、“今天”、“吃了”、“一个”、“汉堡包”。你以为ElasticSearch会这么智能?没错,它对英文是这么智能,但是对我们的中文,只会分成“我”、“今”、“天”、“吃”、“了”、“一”、“个”、“汉”、“堡”、“包”。这样用户还怎么搜索啊。。。所以我们需要一个在ElasticSearch服务端集成一个插件,ElasticSearch-ik插件。有了这个插件,真的可以这么智能了。

所以,带有-ik插件的ElasticSearch服务端怎么装呢?

太麻烦了,所以我选择docker(滑稽.jpg)

(1)加载docker镜像

sudo docker load -i elasticsearch-ik-2.4.6_docker.tar

(2)修改配置文件

elasticsearc-2.4.6/config/elasticsearch.yml第54行,更改ip地址为本机ip地址:

network.host: xxx.xxx.xxx.xxx

如果docker不是运行在开发环境的本机,可以设为0.0.0.0。表示允许所有ip访问此服务器。

(3)运行容器

docker run -d -p 9200:9200 --network=host --name=elasticsearch -v /var/elasticsearch-2.4.6/config:/usr/share/elasticsearch/config delron/elasticsearch-ik:2.4.6-1.0

(4)测试ElasticSearch是否安装成功

curl 'http://xxx.xxx.xxx.xxx:9200/' # IP地址是ElasticSearch的IP

如果测试成功,那么ElasticSearch服务器就已经全部搭建完毕啦,而且这个镜像集中了-ik插件,支持中文分词。搭建完服务端后,就要用客户端了。

使用Haystack对接Elasticsearch客户端:

如果直接在Django项目直接编写代码作为ElasticSearch的客户端,比较复杂,所以借助第三方包Haystack来对接ELasticSearch的客户端。而且使用了Haystack后,以后你换其他的全文搜索服务器时(虽然不太可能换),也不用修改Django项目已经写好的代码。

(1)安装Haystack和ElasticSearch客户端。

pip install drf-haystack # 因为该项目是用DRF写的前后端分离,所以安装的是drf-haystack。如果不用DRF的话,安装的是django-haystack
pip install elasticsearch==2.4.1

(2)配置

1.注册应用

INSTALLED_APPS = [
    ...
    'haystack',
    ...
  ]

2.在项目的配置文件中配置haystack

# 配置haystack全文检索框架
  HAYSTACK_CONNECTIONS = {
    'default': {
      'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
      # 此处为elasticsearch运行的服务器ip地址,端口号默认为9200
      'URL': 'http://xxx.xxx.xxx.xxx:9200/', 
      # 指定elasticsearch建立的索引库的名称
      'INDEX_NAME': 'meiduo', 
    },
  }
  # 当添加、修改、删除数据时,自动更新索引
  HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

(3)创建索引类

创建索引类的目的是指定要保存的字段,ElasticSearch服务器会把mysql的这些字段的数据进行同步。方便查询出来时进行返回。

# goods(应用名)/search_indexes.py  # search_indexes名字不能改,固定
from haystack import indexes
from .models import SKU

class SKUIndex(indexes.SearchIndex, indexes.Indexable):
  """
  SKU索引类
  """  # text表示被查询的字段,用户搜索的是这些字段的值,具体被索引的字段写在另一个文件里。
  text = indexes.CharField(document=True, use_template=True)

  # 保存在索引库中的字段
  id = indexes.IntegerField(model_attr='id')
  name = indexes.CharField(model_attr='name')
  price = indexes.DecimalField(model_attr='price')
  default_image_url = indexes.CharField(model_attr='default_image_url')
  comments = indexes.IntegerField(model_attr='comments')

  def get_model(self):
    """返回建立索引的模型类"""
    return SKU

  def index_queryset(self, using=None):
    """返回要建立索引的数据查询集"""
    return self.get_model().objects.filter(is_launched=True)

(4)指定被索引的字段

# templates/search/indexes/goods(应用名)/sku_text.txt  # 路径和名字是固定的
{{ object.name }}
{{ object.caption }}
{{ object.id }}

(5)生成索引库

python manage.py rebuild_index

此时,索引库成功生成了。接下来就是后端接受用户存过来的查询参数,并返回相应的字段了。

完善后端:

django使用haystack调用Elasticsearch实现索引搜索

刚刚写的SKUIndex可以当做是我们平时写DRF时的model类,接下来还要写序列化器,视图,注册路由。

(1)Haystack序列化器类

from drf_haystack.serializers import HaystackSerializer

class SKUIndexSerializer(HaystackSerializer):
  """
  SKU索引结果数据序列化器
  """
  class Meta:
    index_classes = [SKUIndex]
    fields = ('text', 'id', 'name', 'price', 'default_image_url', 'comments')

(2)Haystack视图

from drf_haystack.viewsets import HaystackViewSet

class SKUSearchViewSet(HaystackViewSet):  # HaystackViewSet继承了RetrieveModelMixin, ListModelMixin, ViewSetMixin, HaystackGenericAPIView,所以可以查一条或多条数据
  """
  SKU搜索
  HaystackViewSet: 查一条,查多条
  """
  index_models = [SKU]
  serializer_class = SKUIndexSerializer

(3)注册路由

router = DefaultRouter()
router.register('skus/search', views.SKUSearchViewSet, base_name='skus_search')
...
urlpatterns += router.urls

(4)访问:127.0.0.1:8080/skus/search/?text=Apple

就可以查询出带有Apple的数据了~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
从零学Python之入门(二)基本数据类型
May 25 Python
使用Python中的tkinter模块作图的方法
Feb 07 Python
Python基于Matplotlib库简单绘制折线图的方法示例
Aug 14 Python
Python嵌套列表转一维的方法(压平嵌套列表)
Jul 03 Python
在IPython中执行Python程序文件的示例
Nov 01 Python
Pandas DataFrame数据的更改、插入新增的列和行的方法
Jun 25 Python
python 机器学习之支持向量机非线性回归SVR模型
Jun 26 Python
Python 进程之间共享数据(全局变量)的方法
Jul 16 Python
django用户登录验证的完整示例代码
Jul 21 Python
Python2比较当前图片跟图库哪个图片相似的方法示例
Sep 28 Python
简单了解python元组tuple相关原理
Dec 02 Python
tensorflow 自定义损失函数示例代码
Feb 05 Python
python 判断三个数字中的最大值实例代码
Jul 24 #Python
Django Celery异步任务队列的实现
Jul 24 #Python
python如何统计代码运行的时长
Jul 24 #Python
Django时区详解
Jul 24 #Python
详解Django定时任务模块设计与实践
Jul 24 #Python
Python3中urlencode和urldecode的用法详解
Jul 23 #Python
对python3中的RE(正则表达式)-详细总结
Jul 23 #Python
You might like
ThinkPHP中处理表单中的注意事项
2014/11/22 PHP
PHP file_get_contents函数读取远程数据超时的解决方法
2015/05/13 PHP
PHP代码实现爬虫记录――超管用
2015/07/31 PHP
详解PHP PDO简单教程
2019/05/28 PHP
jQuery实现的Email中的收件人效果(按del键删除)
2011/03/20 Javascript
javascript实现多栏闭合展开式广告位菜单效果实例
2015/08/05 Javascript
JavaScript Split()方法
2015/12/18 Javascript
jQuery ajax请求返回list数据动态生成input标签,并把list数据赋值到input标签
2016/03/29 Javascript
jQuery页面加载初始化的3种方法(推荐)
2016/06/02 Javascript
JSON 必知必会 观后记
2016/10/27 Javascript
JavaScript基于DOM操作实现简单的数学运算功能示例
2017/01/16 Javascript
Vue制作Todo List网页
2017/04/26 Javascript
Vue2.x中的父子组件相互通信的实现方法
2017/05/02 Javascript
如何通过非数字与字符的方式实现PHP WebShell详解
2017/07/02 Javascript
vue-cli webpack 引入jquery的方法
2018/01/10 jQuery
Puppet的一些技巧
2018/09/17 Javascript
[02:06]2018完美世界全国高校联赛秋季赛开始报名(附彩蛋)
2018/09/03 DOTA
Python简单实现TCP包发送十六进制数据的方法
2016/04/16 Python
Python编程二分法实现冒泡算法+快速排序代码示例
2018/01/15 Python
Python字符串格式化%s%d%f详解
2018/02/02 Python
python实现快速排序的示例(二分法思想)
2018/03/12 Python
Python根据已知邻接矩阵绘制无向图操作示例
2018/06/23 Python
Python3.5迭代器与生成器用法实例分析
2019/04/30 Python
python打印文件的前几行或最后几行教程
2020/02/13 Python
Python龙贝格法求积分实例
2020/02/29 Python
使用CSS3和Checkbox实现JQuery的一些效果
2015/08/03 HTML / CSS
Html5饼图绘制实现统计图的方法
2020/08/05 HTML / CSS
Myprotein加拿大官网:欧洲第一的运动营养品牌
2018/01/06 全球购物
Raleigh兰令自行车美国官网:英国凤头牌自行车
2018/01/08 全球购物
常见的软件开发流程有哪些
2015/11/14 面试题
运动会400米加油稿(8篇)
2014/09/22 职场文书
计划生育工作总结2015
2015/04/03 职场文书
mysql对于模糊查询like的一些汇总
2021/05/09 MySQL
Python NumPy灰度图像的压缩原理讲解
2021/08/04 Python
据Python爬虫不靠谱预测可知今年双十一销售额将超过6000亿元
2021/11/11 Python
Python采集壁纸并实现炫轮播
2022/04/30 Python