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字符串替换示例
Apr 24 Python
在Python的Django框架中编写错误提示页面
Jul 22 Python
在Linux命令行终端中使用python的简单方法(推荐)
Jan 23 Python
Python Json序列化与反序列化的示例
Jan 31 Python
浅谈pyqt5中信号与槽的认识
Feb 17 Python
python抓取需要扫微信登陆页面
Apr 29 Python
pytorch下使用LSTM神经网络写诗实例
Jan 14 Python
python3光学字符识别模块tesserocr与pytesseract的使用详解
Feb 26 Python
python实现俄罗斯方块小游戏
Apr 24 Python
python的链表基础知识点
Sep 13 Python
Python+Xlwings 删除Excel的行和列
Dec 19 Python
selenium3.0+python之环境搭建的方法步骤
Feb 01 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
PHP图片处理类 phpThumb参数用法介绍
2012/03/11 PHP
PHP函数之日期时间函数date()使用详解
2013/09/09 PHP
php上传图片到指定位置路径保存到数据库的具体实现
2013/12/30 PHP
javascript css float属性的特殊写法
2008/11/13 Javascript
11款基于Javascript的文件管理器
2009/10/25 Javascript
js 内存释放问题
2010/04/25 Javascript
JS保存、读取、换行、转Json报错处理方法
2013/06/14 Javascript
文本框回车提交与禁止提交示例
2013/09/27 Javascript
使用javascript实现ListBox左右全选,单选,多选,全请
2013/11/07 Javascript
js如何调用qq互联api实现第三方登录
2014/03/28 Javascript
javascript中attachEvent用法实例分析
2015/05/14 Javascript
jquery实现叠层3D文字特效代码分享
2015/08/21 Javascript
Bootstrap网格系统详解
2016/04/26 Javascript
详解js前端代码异常监控
2017/01/11 Javascript
Bootstrap输入框组件使用详解
2017/06/09 Javascript
借助云开发实现小程序短信验证码的发送
2020/01/06 Javascript
Python应用03 使用PyQT制作视频播放器实例
2016/12/07 Python
Ubuntu安装Jupyter Notebook教程
2017/10/18 Python
Django2.1.3 中间件使用详解
2018/11/26 Python
python实现ftp文件传输系统(案例分析)
2020/03/20 Python
Python闭包装饰器使用方法汇总
2020/06/29 Python
微软俄罗斯官方网站:Microsoft俄罗斯
2016/09/18 全球购物
红色连衣裙精品店:Red Dress Boutique
2018/08/11 全球购物
波兰珠宝品牌:YES
2019/08/09 全球购物
美国名牌香水折扣网站:Hottperfume
2021/02/10 全球购物
Java软件工程师综合面试题笔试题
2013/09/08 面试题
医学生自荐信范文
2013/12/03 职场文书
机电职业生涯规划书范文
2014/03/08 职场文书
不错的求职信范文
2014/07/20 职场文书
2014年英语工作总结
2014/12/20 职场文书
团员年度个人总结
2015/02/26 职场文书
年会邀请函的格式及范文五篇
2019/11/02 职场文书
阿里云Nginx配置https实现域名访问项目(图文教程)
2021/03/31 Servers
Spring Boot 整合 Apache Dubbo的示例代码
2021/07/04 Java/Android
教你在 Java 中实现 Dijkstra 最短路算法的方法
2022/04/08 Java/Android
SQL Server使用CROSS APPLY与OUTER APPLY实现连接查询
2022/05/25 SQL Server