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模拟新浪微博登陆功能(新浪微博爬虫)
Dec 24 Python
在Django中管理Users和Permissions以及Groups的方法
Jul 23 Python
Python编程给numpy矩阵添加一列方法示例
Dec 04 Python
简单谈谈python中的lambda表达式
Jan 19 Python
python字典值排序并取出前n个key值的方法
Oct 17 Python
如何用python写一个简单的词法分析器
Dec 18 Python
通过 Django Pagination 实现简单分页功能
Nov 11 Python
python词云库wordCloud使用方法详解(解决中文乱码)
Feb 17 Python
使用python编写一个语音朗读闹钟功能的示例代码
Jul 14 Python
如何利用python进行时间序列分析
Aug 04 Python
python 办公自动化——基于pyqt5和openpyxl统计符合要求的名单
May 25 Python
Python使用PyYAML库读写yaml文件的方法
Apr 06 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
星际初学者游戏中永远要做的事
2020/03/04 星际争霸
SONY ICF-SW07收音机电路分析
2021/03/02 无线电
什么情况下可以不写PHP的闭合标签“?>”
2014/08/28 PHP
PHP MPDF中文乱码的解决方式
2015/12/08 PHP
PHP十六进制颜色随机生成器功能示例
2017/07/24 PHP
详解PHP版本兼容之openssl调用参数
2018/07/25 PHP
PHP ajax+jQuery 实现批量删除功能实例代码小结
2018/12/06 PHP
浅析PHP中的 inet_pton 网络函数
2019/12/16 PHP
JavaScript中Array 对象相关的几个方法
2006/12/22 Javascript
js中的for如何实现foreach中的遍历
2014/05/31 Javascript
nodejs开发环境配置与使用
2014/11/17 NodeJs
JavaScript中有关一个数组中最大值和最小值及它们的下表的输出的解决办法
2016/07/01 Javascript
jquery 动态合并单元格的实现方法
2016/08/26 Javascript
js HTML5手机刮刮乐代码
2020/09/29 Javascript
Angularjs中数据绑定的实例详解
2017/08/25 Javascript
微信小程序实现左侧滑动导航栏
2020/04/08 Javascript
vue 实现购物车总价计算
2019/11/06 Javascript
[47:20]DAC2018 4.4 淘汰赛 Optic vs Mineski 第一场
2018/04/05 DOTA
Python3.6笔记之将程序运行结果输出到文件的方法
2018/04/22 Python
详解Python正则表达式re模块
2019/03/19 Python
在python plt图表中文字大小调节的方法
2019/07/08 Python
Python 合并多个TXT文件并统计词频的实现
2019/08/23 Python
python Event事件、进程池与线程池、协程解析
2019/10/25 Python
Python操作SQLite/MySQL/LMDB数据库的方法
2019/11/07 Python
python tqdm 实现滚动条不上下滚动代码(保持一行内滚动)
2020/02/19 Python
猫途鹰英国网站:TripAdvisor英国(旅游社区和旅游评论)
2016/08/30 全球购物
红旗方阵解说词
2014/02/12 职场文书
城市创卫标语
2014/06/17 职场文书
大学社团招新的通讯稿
2014/09/10 职场文书
党员个人剖析材料2014
2014/10/08 职场文书
优秀党员申报材料
2014/12/18 职场文书
收银员岗位职责范本
2015/04/07 职场文书
vue使用v-model进行跨组件绑定的基本实现方法
2021/04/28 Vue.js
js实现自动锁屏功能
2021/06/02 Javascript
原生JS实现飞机大战小游戏
2021/06/09 Javascript
spring cloud 配置中心客户端启动遇到的问题
2021/09/25 Java/Android