使用haystack实现Django的全文搜索 -- Elasticsearch搜索引擎

全文搜索:

在使用python进行web开发的时候,免不了须要使用到全文搜索;全文搜索和咱们日常使用的数据库的模糊搜索查询不同,例如在mysql数据库中,若是进行模糊查询,好比 name like '%wang%'这一类的,效率是很是低的;而咱们需求的全文搜索,在效率方面要求是很高的,并且必须可以对中文进行分词处理。html

haystack:

1.介绍:前端

全文搜索的框架;Haystack是 BSD许可的,能够很好地与第三方应用程序配合使用,无需修改源代码,并支持Solr, Elasticsearch, Whoosh和 Xapian四种全文搜索引擎;也就是说,咱们在使用Solr, Elasticsearch, Whoosh和 Xapian这四种搜索引擎的时候,不须要直接对它们直接进行操做,直接经过操做这个haystack框架,就能够进行进行全文搜索;可让你在不修改代码的状况下使用不一样的搜索后端。java

haystack官网python

2.使用:mysql

在Django中使用haystack,能够经过 pip install django-haystack 便可;
固然,若是你的Django项目中,使用到 REST framework,那么能够直接安装 pip install drf-haystackweb

搜索引擎 Elasticsearch

1. 介绍:sql

Elasticsearch官网
Elasticsearch中文学习文档docker

开源的 Elasticsearch 是目前全文搜索引擎的首选。数据库

它能够快速地储存、搜索和分析海量数据。维基百科、Stack Overflow、Github 都采用它。django

Elasticsearch 的底层是开源库 Lucene。可是,你无法直接用 Lucene,必须本身写代码去调用它的接口。Elastic 是 Lucene 的封装,提供了 REST API 的操做接口,开箱即用。全部的功能被集成到一个服务里面,你的应用能够经过简单的RESTful API、各类语言的客户端甚至命令行与之交互。

Elasticsearch 是用Java实现的,Elasticsearch 不支持对中文进行分词创建索引,须要配合扩展elasticsearch-analysis-ik来实现中文分词处理。

2.项目环境介绍:

注意:本文所介绍和使用的Elasticsearch是基于python和Django进行操做演练的。

  • 开发环境:
    python:3.5
    Django:1.11.11
    djangorestframework : 3.9.0
    django-haystack : 2.8.1
    Docker (因为使用的是python,这里演练不许备使用Java,因此用docker来运行Elasticsearch镜像的)

3.Elasticsearch 安装 和 运行:

使用java运行Elasticsearch能够参考:
https://es.xiaoleilu.com/010_Intro/10_Installing_ES.html

咱们这里是使用镜像在docker中运行,镜像下载方式以下:

1.镜像的获取

1.1 能够经过网络pull

docker image pull delron/elasticsearch-ik:2.4.6-1.0

1.2 固然,能够直接下载我这边提供的镜像包:
连接: https://pan.baidu.com/s/1_9mQ9sFmGuPdcwBfHZ6Sxw
提取码: yjee

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

此处注意版本:版本是2.4.6

2.配置

修改elasticsearch的配置文件 elasticsearc-2.4.6/config/elasticsearch.yml第54行,更改ip地址为本机ip地址,好比:

network.host: 127.0.0.1

3.建立docker容器并进行运行

docker run -dti --network=host --name=elasticsearch -v /home/python/elasticsearch-2.4.6/config:/usr/share/elasticsearch/config delron/elasticsearch-ik:2.4.6-1.0

注意:-v 后面的映射路径
/home/python/elasticsearch-2.4.6/config:指的是进行修改过的配置文件存在的路径;
/usr/share/elasticsearch/config delron/elasticsearch-ik:2.4.6-1.0:是镜像文件运行的路径和版本;
文件存放的位置不一样,在进行映射的时候,是不同的

再一次开启这个Elasticsearch镜像时,直接可使用:
docker container start Elasticsearch 便可

haystack与Elasticsearch对接:

Elasticsearch到这一步,已是运行起来了,那么咱们如何来对其进行操做呢?
固然是使用咱们haystack来进行对接;想要进行对接的话,除了以前安装过的drf-haystack,还须要在python中安装elasticsearch==2.4.1

1.基于python的客户端的安装:

pip install elasticsearch==2.4.1

这里须要提醒的是,版本是须要特别注意的,若是在安装的时候,后面不具体描述版本号,默认会下载最新的版本,可是兼容问题有待提高,因此为了避免必要的bug,能够按照个人版本进行对应。

2.配置
经过django的haystack来操做,因此在django中进行相关配置是必不可少的:

settings.py中添加下面的配置信息:

1.应用注册:

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

2.使用haystack须要进行的配置:

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
        'URL': 'http://127.0.0.1:9200/',  # 此处为elasticsearch运行的服务器ip地址,端口号固定为9200
        'INDEX_NAME': 'djangotest',  # 指定elasticsearch创建的索引库的名称
    },
}


#当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

HAYSTACK_SIGNAL_PROCESSOR 的配置保证了在Django运行起来后,有新的数据产生时,haystack仍然可让Elasticsearch实时生成新数据的索引;固然,也是能够手动进行索引的生成:

python manage.py rebuild_index

3.索引的建立

1.索引文件建立:
在子应用目录下,添加一个索引,名为: search_indexes.py;
下面的代码在goods/search_indexes.py

from haystack import indexes
 ① # 修改此处,改为你本身的model
from goods.models import Goods    (Goods是子应用goods中的一个模型类) 

② #修改此处,类名为模型类的名称+Index,好比模型类为Goods,则这里类名为GoodsIndex
class GoodsIndex(indexes.SearchIndex, indexes.Indexable):
    # 指明哪些字段产生索引,产生索引的字段,会做为前端检索查询的关键字;
    # document是指明text是使用的文档格式,产生字段的内容在文档中进行描述;
    # use_template是指明在模板中被声明须要产生索引;
    text = indexes.CharField(document=True, use_template=True)

③ # 此外能够存在,能够不存在,看具体须要的数据
    """下面这些字段,在索引类中进行申明,在REST framework中,索引类的字段能够被做为索引查询结果返回数据额来源"""
    id = indexes.IntegerField(model_attr='id')
    name = indexes.CharField(model_attr='name')
    price = indexes.DecimalField(model_attr='price')

    """也就是说,前端在索引的时候,能够按照text=xxx,也能够按照id=xxx,name=xxx等,咱们的数据返回也是返回id,name,price """

④ # 修改此处,返回的是你本身的model
    def get_model(self):
        """获取模型类"""
        return Goods
        
⑤# 修改return 能够修改返回查询集的内容,好比返回时,有什么条件限制的时候
    def index_queryset(self, using=None):
        """声明知足索引要求的返回的查询集"""
        return Goods.objects.all()

说明:

1.在进行索引类的使用时,修改上述代码中的①②③④⑤便可;
2.此文件指定如何经过已有数据来创建索引。get_model处,直接将django中的model放过来,即可以直接完成索引啦,无需关注数据库读取、索引创建等细节。
3.text=indexes.CharField一句,指定了将模型类中的哪些字段创建索引,而use_template=True说明后续咱们还要指定一个模板文件,告知具体是哪些字段;

2.指定索引使用的模板文件/指名须要创建索引的字段:

在项目的“templates/search/indexes/应用名称/”下建立“模型类名称_text.txt”文件
好比:
templates/search/indexes/goods/sku_text.txt:

这个是模板文件的路径,此文件指定将模型中的哪些字段创建索引
indexes: 用于索引; 
goods: 有索引的子应用名称; 
sku_text: sku是指明那个模型类,text是指明那个字段
在这里插入图片描述
文件中写入的内容以下:

{{ object.字段1 }}
{{ object.字段2 }}
{{ object.字段3 }}

3.视图函数和序列化器:

(下面的视图函数和序列化器,若是你没有使用REST Framework,直接使用的Django话,那么能够直接写django中的视图函数,进行请求和响应数据的处理)

RESTFramewirk中的haystack中提供了相应的视图集和序列化器,能够直接进行使用:

建立haystack序列化器

from drf_haystack.serializers import HaystackSerializer

class GoodsIndexSerializer(HaystackSerializer):
    """
    Goods索引结果数据序列化器
    """
    class Meta:
        index_classes = [GoodsIndex]
        fields = ('text', 'id', 'name', 'price')

注意fields属性的字段名与GoodsIndex类的字段对应;

建立视图

from drf_haystack.viewsets import HaystackViewSet

class GoodsSearchViewSet(HaystackViewSet):
    """
    Goods搜索
    """
    index_models = [Goods]

    serializer_class = GoodsIndexSerializer

4.路由

路由( haystack 视图函数用的是视图集,因此经过下面的方式添加路由):

from rest_framework.routers import DefaultRouter

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