Django之Haystack对接搜索引擎框架Elasticsearch

embedded/2024/9/25 16:35:45/

Django之Haystack对接Elasticsearch

  • Haystack
    • 概述
    • 安装依赖
    • 环境准备
    • Haystack配置
  • Haystack建立数据索引
    • 创建模型对象
    • 创建搜索索引类
    • 创建模板文件
    • 执行数据库迁移
    • 生成索引
    • 渲染模板
    • 执行测试
  • 搜索请求和结果渲染的自定义处理
    • 概述
    • 创建搜索视图
    • 配置URL
    • 创建搜索模板
    • 自定义结果渲染
    • 执行测试
  • 其他
    • 添加分页功能
    • 自定义搜索查询
    • 使用Facets
    • 高级排序
    • 使用拼音搜索或模糊搜索

Haystack_1">Haystack

概述

Haystack是在Django中对接搜索引擎的框架,搭建用户和搜索引擎之间的沟通桥梁。它提供了一种简化的方式来集成不同的搜索引擎,如Elasticsearch、Whoosh、Solr等。

Elasticsearch的底层是开源库Lucene。Python是没法直接使用Lucene,必须写代码去调用它的接口。因此,在Django中可以通过使用Haystack对接 Elasticsearch服务端

Haystack的主要功能包括:

统一接口:Haystack为多个搜索引擎提供了统一的API,使得在不同的搜索引擎之间切换变得简单。搜索索引:它允许开发者为Django模型创建搜索索引,从而能够对模型中的数据进行高效的搜索。查询构建:Haystack提供了简洁的查询构建工具,支持复杂的搜索条件和过滤。模板支持:可以通过模板轻松自定义搜索结果的展示。灵活性:Haystack支持多种后端搜索引擎,开发者可以根据项目需求选择最合适的搜索解决方案。

文档:https://docs.haystacksearch.org/en/master/tutorial.html

安装依赖

首先,需要安装django-haystackelasticsearch

在Django项目中安装Haystack

pip install django-haystack

注意:使用elasticsearch时,使用如下命令安装

# pip install elasticsearch==7.5.1pip install "django-haystack[elasticsearch]"

环境准备

创建应用模块product

python manage.py startapp product

在Django项目的settings.py文件中,注册应用product,同时将haystack添加到INSTALLED_APPS

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

在项目路径下注册路由

urlpatterns = [# path('admin/', admin.site.urls),path('search/', include('haystack.urls')),path('product/', include('product.urls')),
]

Haystack_57">Haystack配置

在Django的settings.py文件中配置Haystack和Elasticsearch

HAYSTACK_CONNECTIONS = {'default': {# 这里使用Elasticsearch7.x版本,如果使用其他版本,请相应地修改ENGINE的值'ENGINE': 'haystack.backends.elasticsearch7_backend.Elasticsearch7SearchEngine',# Elasticsearch服务器ip地址,端口号固定为9200'URL': 'http://127.0.0.1:9200/',# Elasticsearch建立的索引库的名称'INDEX_NAME': 'demo',},
}# 当数据库改变时,会自动更新索引
# Haystack可以让Elasticsearch实时生成新数据的索引,即当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'# 控制每页显示数量
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 20

Haystack_78">Haystack建立数据索引

创建模型对象

在product子应用的models.py文件创建模型对象

from django.db import modelsclass Product(models.Model):name = models.CharField(max_length=20, verbose_name='名称')price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='单价')stock = models.IntegerField(default=0, verbose_name='库存')is_existed = models.BooleanField(default=True, verbose_name='是否上架')class Meta:db_table = 'tb_product'verbose_name = '产品'verbose_name_plural = verbose_namedef __str__(self):return '%s: %s' % (self.id, self.name)

创建搜索索引类

创建一个搜索索引类来定义要搜索的模型,指明让搜索引擎对哪些字段建立索引,即通过哪些字段的关键字来检索数据,通常在应用目录下创建一个search_indexes.py文件

在product子应用的目录下创建search_indexes.py文件,在这个文件下写索引类

from haystack import indexesfrom .models import Product# ProductIndex索引数据模型类
class ProductIndex(indexes.SearchIndex, indexes.Indexable):# text表示被查询的字段,用户搜索的是这些字段的值,具体被索引的字段写在另一个文件里。text = indexes.CharField(document=True, use_template=True)stock = indexes.IntegerField(model_attr='stock')price = indexes.FloatField(model_attr='price')def get_model(self):# 返回建立索引的模型类return Productdef index_queryset(self, using=None):# 返回要建立索引的数据查询集return self.get_model().objects.all()

注意:

  • 类名必须是需要检索的ModelName+Index,如:Product模型类+Index,即ProductIndex

  • 每个索引类必须有且只能有一个字段为document=True,代表haystack和搜索引擎将使用此字段的内容作为索引进行检索。其他的字段只是附属的属性,方便调用,并不作为检索数据。

  • 如果使用一个字段设置了document=True,则一般约定此字段名为text,表名该字段是主要进行关键字查询的字段,用于构造索引,只不过具体构造索引的值写在另一个文件内。

  • haystack提供了use_template=True在text字段,允许使用数据模板去建立搜索引擎索引的文件

  • stock 、price 用于以索引查询到的返回内容

  • get_model方法用于指明建立索引的对应模型

  • index_queryset方法用于返回建立索引的数据查询集

创建模板文件

templates目录下创建search/indexes/yourapp/yourmodel_text.txt字段索引值模板文件,在该文件中定义要索引的字段

例如:

{{ object.field_name }}
yourapp:实际应用名称yourmodel:实际模型名称field_name:要索引的实际字段

注意:

这个路径是固定的,如果不按照这个路径配置,就需要在text字段内使用template_name 参数,指定模板文件

例如:这里在templates目录下创建search/indexes/product/product_text.txt文件,具体索引字段如下:

{{ object.name }}
{{ object.price }}

模板文件意思:

当将关键词通过text参数名传递时,此模板指明Product的name、price作为text字段的索引值来进行关键字索引查询,即作为索引的方向

执行数据库迁移

配置连接数据库信息

DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','HOST': '127.0.0.1',  # 数据库主机'PORT': 3306,  # 数据库端口'USER': 'root',  # 数据库用户名'PASSWORD': '123456',  # 数据库用户密码'NAME': 'demo'  # 数据库名字}
}

生成迁移文件,让 Django 知道模型有一些变更

python manage.py makemigrations

创建表结构,同步到数据库中

python manage.py migrate

插入Product模型类对应的tb_product表数据

INSERT INTO `demo`.`tb_product` (`id`, `name`, `price`, `stock`, `is_existed`) VALUES (1, '1号手机', 999.00, 23, 1);
INSERT INTO `demo`.`tb_product` (`id`, `name`, `price`, `stock`, `is_existed`) VALUES (2, '2号手机', 1999.00, 98, 1);
INSERT INTO `demo`.`tb_product` (`id`, `name`, `price`, `stock`, `is_existed`) VALUES (3, '3号手机', 3999.00, 56, 1);
INSERT INTO `demo`.`tb_product` (`id`, `name`, `price`, `stock`, `is_existed`) VALUES (4, '4号手机', 4999.00, 234, 1);
INSERT INTO `demo`.`tb_product` (`id`, `name`, `price`, `stock`, `is_existed`) VALUES (5, '5号手机', 5999.00, 21, 1);

生成索引

运行以下命令来创建并初始化Elasticsearch索引

python manage.py rebuild_index
(django) D:\WorkSpace\Python\django_project>python manage.py rebuild_index
WARNING: This will irreparably remove EVERYTHING from your search index in connection 'default'.
Your choices after this are to restore from backups or rebuild via the `rebuild_index` command.
Are you sure you wish to continue? [y/N] y
Removing all documents from your index because you said so.
All documents removed.
Indexing 5 产品

查看ES,发现索引已创建,并且tb_product表中数据根据索引类配置已生产相应索引数据
在这里插入图片描述

注意:本人在生成初始索引时,遇到如下异常:

haystack.exceptions.MissingDependency: The 'elasticsearch' backend requires the installation of 'elasticsearch'. Please refer to the documentation

最初直接指定版本安装es:

pip install elasticsearch==7.5.1

经过一番折腾,阅读官方文档,推测很有可能是Haystack与Elasticsearch版本不兼容导致的。参考官方文档,使用如下命令安装Elasticsearch,问题得以解决。

pip install "django-haystack[elasticsearch]"

渲染模板

templates目录下创建search/search.html渲染模板文件,用于接收和渲染全文检索的结果。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form method="get" action="/search/"><input type="text" name="q" placeholder="产品名称"><input type="submit" name="" value="搜索">
</form><hr><div>搜索关键字: <span>{{ query }}</span><hr>总页数: <span>{{ page.paginator.num_pages }}</span><hr>{% for result in page.object_list %}<li><span>{{ result.object.name }}</span><span>{{ result.object.price }}</span></li>{% empty %}<span>查询无结果</span>{% endfor %}
</div><!-- 分页导航 -->
<div>{% if page.has_previous %}<a href="?q={{ query }}&page={{ page.previous_page_number }}">上一页</a>{% endif %}{% for num in page.paginator.page_range %}{% if page.number == num %}<span>{{ num }}</span>{% else %}<a href="?q={{ query }}&page={{ num }}">{{ num }}</a>{% endif %}{% endfor %}{% if page.has_next %}<a href="?q={{ query }}&page={{ page.next_page_number }}">下一页</a>{% endif %}
</div></body>
</html>

执行测试

访问:http://127.0.0.1:8000/search/搜索
在这里插入图片描述

直接访问:http://127.0.0.1:8000/search/?q=手机
在这里插入图片描述

分页搜索:http://127.0.0.1:8000/search/?q=手机&page=2
在这里插入图片描述

搜索请求和结果渲染的自定义处理

概述

自动处理

当在Django中使用 Haystack 和 Elasticsearch 进行搜索时,可以通过注册 haystack.urls 来处理搜索相关的 URL 路由。这样做的好处是,Haystack 提供了默认的视图和 URL 配置,可以方便地处理搜索请求并渲染搜索结果。

手动处理

如果想手动处理搜索请求和渲染结果,而不使用 Haystack 提供的默认视图和 URL 配置,可以编写自己的视图函数来执行搜索操作并将搜索结果传递给模板进行渲染。

创建搜索视图

首先,在应用的views.py中创建一个搜索视图。这个视图将处理GET请求中的搜索关键词,并使用Haystack进行搜索。

from haystack.query import SearchQuerySetdef searchView(request):query = request.GET.get('q') # 获取搜索关键词if query:search_results = SearchQuerySet().filter(text=query) # 根据关键词过滤结果else:print("kong")search_results = [] # 如果没有关键词,返回空结果return render(request, 'product/product_search.html', {'search_results': search_results})

配置URL

在应用的urls.py中配置搜索视图的URL。

urlpatterns = [path('search/', views.searchView),
]

创建搜索模板

在模板目录中创建一个名为search.html的模板文件。这个模板将用于展示搜索表单和结果。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form method="get" action="/product/search/"><input type="text" name="q" placeholder="产品名称"><input type="submit" name="" value="搜索">
</form>
<hr>
<div>{% for result in search_results  %}<li><span>{{ result.object.name }}</span><span>{{ result.object.price }}</span></li>{% empty %}<span>查询无结果</span>{% endfor %}
</div></body>
</html>

自定义结果渲染

在模板中,可以访问搜索结果的不同字段。例如,如果模型有多个字段,可以在循环中展示这些字段。

<div>{% for result in search_results  %}<li><span>{{ result.object.name }}</span><span>{{ result.object.price }}</span></li>{% empty %}<span>查询无结果</span>{% endfor %}
</div>

执行测试

访问:http://127.0.0.1:8000/product/search搜索
在这里插入图片描述

其他

Haystack在Django中提供了一些高级用法,可以帮助实现更复杂和灵活的搜索功能。

添加分页功能

如果搜索结果较多,可以考虑实现分页功能。可以使用Django的内置分页工具:

from django.core.paginator import Paginatordef search_view(request):query = request.GET.get('q')results = SearchQuerySet().all()if query:results = results.filter(content=query)paginator = Paginator(results, 10)  # 每页10个结果page_number = request.GET.get('page')page_obj = paginator.get_page(page_number)return render(request, 'product/product_search.html', {'page_obj': page_obj, 'query': query})

在模板中,添加分页链接:

<div><span>{{ page_obj.paginator.count }} 条结果</span>
</div>
<ul>{% for result in page_obj %}<li><a href="{{ result.object.get_absolute_url }}">{{ result.object.title }}</a><p>{{ result.object.description }}</p></li>{% empty %}<li>没有找到结果。</li>{% endfor %}
</ul><div><span>页码: </span><span class="pagination">{% if page_obj.has_previous %}<a href="?q={{ query }}&page=1">第一页</a><a href="?q={{ query }}&page={{ page_obj.previous_page_number }}">上一页</a>{% endif %}<span>{{ page_obj.number }}</span>{% if page_obj.has_next %}<a href="?q={{ query }}&page={{ page_obj.next_page_number }}">下一页</a><a href="?q={{ query }}&page={{ page_obj.paginator.num_pages }}">最后一页</a>{% endif %}</span>
</div>

自定义搜索查询

可以使用Haystack的SearchQuerySet来构建复杂的查询。

使用filter()、exclude()和order_by()等方法来定制搜索结果

from haystack.query import SearchQuerySetresults = SearchQuerySet().filter(content='搜索关键词').exclude(author='某个作者').order_by('-date')

使用Facets

分面搜索允许对搜索结果进行分类和过滤。

from haystack.query import SearchQuerySetdef search_view(request):query = request.GET.get('q')sqs = SearchQuerySet().filter(content=query)facets = sqs.facet('category')  # 假设有一个category字段return render(request, 'product/product_search.html', {'results': sqs, 'facets': facets})

高级排序

可以根据多个字段进行排序,或者使用自定义的排序逻辑

results = SearchQuerySet().filter(content='关键词').order_by('field1', '-field2')

使用拼音搜索或模糊搜索

在某些情况下,可能需要支持拼音搜索或模糊搜索,可以通过自定义查询来实现

results = SearchQuerySet().filter(content__contains='拼音关键词')

http://www.ppmy.cn/embedded/116712.html

相关文章

在Ubuntu中安装多个版本CMake

安装教程请参考这里&#xff0c;只不过不需要修改环境变量&#xff0c;这一步由update-alternatives代理。查看Ubuntu系统版本 cmake --version使用update-alternatives管理多个版本 以下的所有版本号都需要根据自己的情况修改 sudo mv /usr/bin/cmake /usr/bin/cmake-3.10.2…

SqlSugar的where条件中使用可空类型报语法错误

SQLServer数据表中有两列可空列&#xff0c;均为数值类型&#xff0c;同时在数据库中录入测试数据&#xff0c;Age和Height列均部分有值。   使用SqlSugar的DbFirst功能生成数据库表类&#xff0c;其中Age、Height属性均为可空类型。   当Where函数中的检索条件较多时&a…

常用微服务网关详解,底层设计逻辑介绍

1 API网关基础 1.1 什么是API网关 API网关是一个服务器&#xff0c;是系统的唯一入口。 从面向对象设计的角度看&#xff0c;它与外观模式类似。 API网关封装了系统内部架构&#xff0c;为每个客户端提供一个定制的API。它可能还具有其它职责&#xff0c;如身份验证、监控、…

QT编译之后的debug包下运行程序双击运行出现无法定位程序输入点__gxx_personlity_seh0于动态链接库

1.出现这个错误的原因是&#xff1a; 缺少如下文件&#xff1a; 2.解决方法&#xff1a; 在运行程序.exe所在的目录执行&#xff1a;windeployqt untitled.exe&#xff08;指打包的运行程序&#xff09; 3.如果执行提示由于找不到qt5core.dll,无法继续执行代码和无法识别win…

帆软通过JavaScript注入sql,实现数据动态查询

将sql语句设置为参数 新建数据库查询 设置数据库查询的sql语句 添加控件 JavaScript实现sql注入 添加事件 编写JavaScript代码 //获取评价人id var pjrid this.options.form.getWidgetByName("id").getValue();//显示评价人id alert("评价人&#xff1a;&…

第六章 输入和输出处理(IO流)

File类操作文件 public static void main(string[] args){try {//创建File对象// 绝对路径相对路径string path "D:/4072/1/":String fileName "1.txt";File file new File(path);if(!file.exists()&&!file.isDirectory()){ file.mkdirs();//创…

AI视觉算法盒是什么?如何智能化升级网络摄像机,守护全方位安全

在智能化浪潮席卷全球的今天&#xff0c;以其创新技术引领行业变革&#xff0c;推出的集高效、智能、灵活于一体的AI视觉算法盒。这款革命性的产品&#xff0c;旨在通过智能化升级传统网络摄像机&#xff0c;为各行各业提供前所未有的安全监控与智能分析能力&#xff0c;让安全…

记录网络IP自动获取到169.254.x.x的解决过程

总结&#xff1a; 出现断网并且显示未识别的网络时&#xff0c;可能会存在几种情况&#xff1a; IP冲突导致的无法上网。网卡配置错误导致的无法上网。网络未连通导致无法通过路由DHCP获取IP&#xff0c;导致的无法上网。即使交换机没有WAN口网线&#xff0c;电脑连接LAN口也会…