Django全文检索实现:HayStack-+-Whoosh-+-Jieba
涉及到的工具 haystack是django的开源搜索框架,该框架支持**Solr**, Elasticsearch, Whoosh, **Xapian搜索引擎,不用更改代码,直接切换引擎,减少代码量。 搜索引擎使用Whoosh,这是一个由纯Python实现的全文搜索引擎,没有二进制文件等,比较小巧,配置比较简单,当然性能自然略低。 中文分词Jieba,由于Whoosh自带的是英文分词,对中文的分
目录10 个章节
涉及到的工具
-
haystack是django的开源搜索框架,该框架支持**Solr**, Elasticsearch, Whoosh, **Xapian搜索引擎,不用更改代码,直接切换引擎,减少代码量。
-
搜索引擎使用Whoosh,这是一个由纯Python实现的全文搜索引擎,没有二进制文件等,比较小巧,配置比较简单,当然性能自然略低。
-
中文分词Jieba,由于Whoosh自带的是英文分词,对中文的分词支持不是太好,故用jieba替换whoosh的分词组件。
Model配置
class Post(models.Model):
"""post 文章页面"""
id = models.AutoField(primary_key=True, max_length=20)
name = models.CharField(max_length=200, help_text="Post文章的URL链接名称")
post_category = models.ForeignKey(PostCategory, blank=True, null=True, default=None, on_delete=models.SET_NULL)
post_author = models.ForeignKey(PostAuthor, blank=True, null=True, default=None, on_delete=models.SET_NULL)
post_date = models.DateTimeField(default=timezone.now, help_text="创建日期")
post_modified = models.DateTimeField(default=timezone.now, help_text="修改日期")
post_content = models.TextField(help_text="html格式的页面内容,仅在page类型才可用")
post_title = models.CharField(max_length=200)
post_summary = models.TextField(max_length=300, blank=True)
post_status = models.CharField(choices=(('publish', '已发布'), ('draft', '草稿')), default='publish', max_length=20,
help_text="页面状态")
# post_slug = models.CharField(max_length=200, help_text="URL链接名称")
def __str__(self):
return self.post_title
安装Python模块
- whoosh
- django-haystack
- jieba
修改 whoosh 的分析器
将文件whoosh_backend.py(该文件路径为python路径/lib/python版本/site-packages/haystack/backends/whoosh_backend.py)拷贝到app文件夹下面,修改如下
添加from jieba.analyse import ChineseAnalyzer
修改为如下
schema_fields[field_class.index_fieldname] =
TEXT(stored=True, analyzer=ChineseAnalyzer(),
field_boost=field_class.boost)
修改settings.py
- 添加 Haystack 到Django的 INSTALLED_APPS
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'Core.whoosh_backend.WhooshEngine',
'PATH': os.path.join(BASE_DIR, 'Resources', 'index', 'whoosh'),
},
}
注:
Core是我的App名称,请根据情况替换成你自己的App文件夹名称PATH为存放Whoosh索引文件的文件夹。- 其他引擎的配置请查阅官方文档。
建立索引
在需要搜索功能的App文件夹下建立search_indexes.py文件,用于创建索引。
内容如下:
import datetime
from haystack import indexes
from Core import models
class PostIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
post_author = indexes.CharField(model_attr='post_author')
post_date = indexes.DateTimeField(model_attr='post_date')
def get_model(self):
return models.Post
def index_queryset(self, using=None):
"""Used when the entire index for model is updated."""
return self.get_model().objects.filter(post_date__lte=datetime.datetime.now())
每个索引里面必须有且只能有一个字段为document=True,这代表haystack 和搜索引擎将使用此字段的内容作为索引进行检索(primary field)。其他的字段只是附属的属性,方便调用,并不作为检索数据。
注意:如果使用一个字段设置了document=True,则一般约定此字段名为text,这是在SearchIndex类里面一贯的命名,以防止后台混乱,当然名字你也可以随便改,不过不建议改。
并且,haystack提供了use_template=True在text字段,这样就允许我们使用数据模板去建立搜索引擎索引的文件,使用方便(官方推荐,当然还有其他复杂的建立索引文件的方式,目前我还不知道),数据模板的路径为yourapp/templates/search/indexes/yourapp/classname_text.txt,例如本例子为Resources/templates/search/indexes/Core/post_text.txt
文件名必须为要索引的类名_text.txt,其内容为:
{{ object.post_title }}
{{ object.post_author }}
{{ object.post_content }}
{{ object.post_summary }}
这个数据模板的作用是对
- Post.post_title
- Post.post_author
- Post.post_content
- Post.post_summary
这四个字段建立索引,当检索的时候会对这三个字段做全文检索匹配。
配置URL
在链接配置中加入
path('search/', include('haystack.urls')),
编写search.html
在 templates/search/ 文件夹下添加 search.html 文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>Search</h2>
<form method="get" action=".">
<table>
{{ form.as_table }}
<tr>
<td> </td>
<td>
<input type="submit" value="Search">
</td>
</tr>
</table>
{% if query %}
<h3>Results</h3>
{% for result in page.object_list %}
<p>
<a href="{{ result.object.get_absolute_url }}">{{ result.object.post_title }}</a>
</p>
{% empty %}
<p>No results found.</p>
{% endfor %}
{% if page.has_previous or page.has_next %}
<div>
{% if page.has_previous %}<a href="?q={{ query }}&page={{ page.previous_page_number }}">{% endif %}«
Previous{% if page.has_previous %}</a>{% endif %}
|
{% if page.has_next %}<a href="?q={{ query }}&page={{ page.next_page_number }}">{% endif %}Next »
{% if page.has_next %}</a>{% endif %}
</div>
{% endif %}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
</form>
</body>
</html>
重新建立索引
使用python manage.py rebuild_index或者使用update_index命令。
在 settings.py 里加入以下配置,实现自动刷新索引。
HAYSTACK_SIGNAL_PROCESSOR = "haystack.signals.RealtimeSignalProcessor"
这样就OK啦,可以打开 网站/search 试试看搜索功能了~
SearchQuerySet 初窥
我发现网络上的资料都没有介绍到,于是在官网翻看了一下。 文档地址:https://django-haystack.readthedocs.io/en/v2.8.1/searchqueryset_api.html#ref-searchqueryset-api
这个 SearchQuerySet 类似于DjangoORM框架里的 QuerySet,熟悉Django的同学应该很快能上手,不过做结果处理的话会比较麻烦。
用到SearchQuerySet一般都是用于Ajax API,我发现之前用于 QuerySet 的序列化器不能用于 SearchQuerySet,要做的话还需要做一些修改。
这个等有时间再继续改。或者我再看看官网文档,研究一下。
用法挺简单的,看一下官方文档就行,已经写得很清楚了~
_EOF_
Django全文检索实现:HayStack-+-Whoosh-+-Jieba
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
Django数据库性能优化之使用Python集合操作
前言 最近有个新需求: 人员基础信息(记作人员A),10w 某种类型的人员信息(记作人员B),1000 要求在后台上(Django Admin)分别展示:已录入A的人员B列表、未录入的人员B列表 团队的DBA提议使用视图可以解决这个问题(不愧是搞数据库的) PS:起先我觉得Django的Model是直接管理数据库表的,使用Model来映射数据库模型怕是有一定的麻烦,不过查了一下资料发现并不会~ 只
2022-08-26 · Django · 约 1 分钟
DjangoRestFramework框架三种分页功能的实现 - 在DjangoStarter项目模板中封装
前言 继续Django后端开发系列文章。刚好遇到一个分页的需求,就记录一下。 Django作为一个“全家桶”型的框架,本身啥都有,分页组件也是有的,但默认的分页组件没有对API开发做优化,所以DjangoRestFramework这个专门写API的框架又把Django的分页组件包装了一层,集成在viewsets里的时候会更方便。 不过我们不可能一直用viewsets,有一部分API还是要用自由度更
2022-08-26 · Django · 约 1 分钟
Django-Filter介绍与刁钻需求的实现方法
Django-Filter是一个非常好用的第三方库,很好的利用了Django ORM的特性,可以使用很少的代码就扩展原有的接口,实现多种筛选功能~ 场景 Model定义的部分代码,可以看到需求模型包括了 关键词 keyword、区域 region、需求状态 require_status,这三个字段 class Require(models.Model): 需求 keyword =
2021-12-18 · Django · 约 1 分钟
实测 Django 6.0:模版片段、后台任务、CSP 安全,三大特性体验报告
呵,连WebSocket都没塞进去就敢叫大版本更新?不过模版片段和内置后台任务总算让Django像个现代框架了,至少写HTMX时不用再到处塞碎片文件。原生CSP?早该有了。至于抛弃Python 3.11——跟不上时代的版本留着也是累赘。
2026-01-20 · Django · 约 1 分钟
讨论
共 0 条加载评论中…