稍微深度踩坑haystack + whoosh + jieba

说到django的全文检索,网上基本推荐的都是 haystack + whoosh + jieba 的方案。
由于我的需求对搜索时间敏感度较低,但是要求不能有数据的错漏。
但是没有调试的情况下,搜索质量真的很差,搞得我都想直接用Like搜索数据库算了。
但是峰回路转,还是让我找到几个信息,稍微优化了一下搜索结果。

1.haystack

haystack这层我增加了一个模糊搜索,即原本的text='q’变成了text__contains=‘q’。
搜索从原本的的content切换成了contains,不再需要完全匹配就能命中。
比如词“下雨”在用content的时候搜“雨”是没办法命中的,换成contain之后就可以了。(需要搭配第二点中的自定义全量分词,默认分词不行。具体原因不知,不过应该不是index的问题,因为我测试过用默认分词rebuild_index后,再切换ChineseAnalyzer而不重新rebuild_index依然可以搜索到结果,猜测原因应该是对搜索词的分词,但是我就一个字有啥好分词的?有懂得大佬麻烦教我一下。)

class LynSearchForm(SearchForm):def search(self):if not self.is_valid():return self.no_query_found()if not self.cleaned_data.get("q"):return self.no_query_found()# 原设置搜索条件的语句,被我替换成下面的语句# sqs = self.searchqueryset.auto_query(self.cleaned_data["q"]) sqs = self.searchqueryset.filter(text__contains=self.cleaned_data["q"])if self.load_all:sqs = sqs.load_all()return sqs

我写这篇文章的时间是2023年8月,haystack已经进行了大的更新。从原本的views.SearchView 切换到了 generic_views.SearchView。把接口都给换了,然后代码里面还是旧的内容,各位看官看的时候要注意。

新流程以SearchView为例:

form = self.get_form(form_class)
self.queryset = form.search()
context = self.get_context_data({self.form_name: form})

get_context_data是django的view的函数,所以我们要做的是在form上面做手脚。

2.whoosh + jieba

除了上面的操作外,还需要对jieba的ChineseAnalyzer进行自定义,修改成全量分词。
代码来源 州的先生 大佬写的MrDoc我从中受益良多,大家有兴趣可以多多支持

# coding:utf-8
# @文件: chinese_analyzer.py
# @创建者:州的先生
# #日期:2020/11/22
# 博客地址:zmister.comfrom whoosh.compat import u, text_type
from whoosh.analysis.filters import LowercaseFilter
from whoosh.analysis.filters import StopFilter, STOP_WORDS
from whoosh.analysis.morph import StemFilter
from whoosh.analysis.tokenizers import default_pattern
from whoosh.lang.porter import stem
from whoosh.analysis import Tokenizer, Token
from whoosh.util.text import rcompile
import jiebaclass ChineseTokenizer(Tokenizer):"""使用正则表达式从文本中提取 token 令牌。>>> rex = ChineseTokenizer()>>> [token.text for token in rex(u("hi there 3.141 big-time under_score"))]["hi", "there", "3.141", "big", "time", "under_score"]"""def __init__(self, expression=default_pattern, gaps=False):""":param expression: 一个正则表达式对象或字符串,默认为 rcompile(r"\w+(\.?\w+)*")。表达式的每一个匹配都等于一个 token 令牌。第0组匹配(整个匹配文本)用作 token 令牌的文本。如果你需要更复杂的正则表达式匹配处理,只需要编写自己的 tokenizer 令牌解析器即可。:param gaps: 如果为 True, tokenizer 令牌解析器会在正则表达式上进行分割,而非匹配。"""self.expression = rcompile(expression)self.gaps = gapsdef __eq__(self, other):if self.__class__ is other.__class__:if self.expression.pattern == other.expression.pattern:return Truereturn Falsedef __call__(self, value, positions=False, chars=False, keeporiginal=False,removestops=True, start_pos=0, start_char=0, tokenize=True,mode='', **kwargs):""":param value: 进行令牌解析的 Unicode 字符串。:param positions: 是否在 token 令牌中记录 token 令牌位置。:param chars: 是否在 token 中记录字符偏移。:param start_pos: 第一个 token 的位置。例如,如果设置 start_pos=2, 那么 token 的位置将是 2,3,4,...而非 0,1,2,...:param start_char: 第一个 token 中第一个字符的偏移量。例如, 如果设置 start_char=2, 那么文本 "aaa bbb" 解析的两个字符串位置将体现为 (2,5),(6,9) 而非 (0,3),(4,7).:param tokenize: 如果为 True, 文本应该被令牌解析。"""# 判断传入的文本是否为字符串,如果不为字符串则抛出assert isinstance(value, text_type), "%s is not unicode" % repr(value)t = Token(positions, chars, removestops=removestops, mode=mode,**kwargs)if not tokenize:t.original = t.text = valuet.boost = 1.0if positions:t.pos = start_posif chars:t.startchar = start_chart.endchar = start_char + len(value)yield telif not self.gaps:# The default: expression matches are used as tokens# 默认情况下,正则表达式的匹配用作 token 令牌# for pos, match in enumerate(self.expression.finditer(value)):#     t.text = match.group(0)#     t.boost = 1.0#     if keeporiginal:#         t.original = t.text#     t.stopped = False#     if positions:#         t.pos = start_pos + pos#     if chars:#         t.startchar = start_char + match.start()#         t.endchar = start_char + match.end()#     yield tseglist = jieba.cut(value, cut_all=True)for w in seglist:t.original = t.text = wt.boost = 1.0if positions:t.pos = start_pos + value.find(w)if chars:t.startchar = start_char + value.find(w)t.endchar = start_char + value.find(w) + len(w)yield telse:# When gaps=True, iterate through the matches and# yield the text between them.# 当 gaps=True, 遍历匹配项并在它们之间生成文本。prevend = 0pos = start_posfor match in self.expression.finditer(value):start = prevendend = match.start()text = value[start:end]if text:t.text = textt.boost = 1.0if keeporiginal:t.original = t.textt.stopped = Falseif positions:t.pos = pospos += 1if chars:t.startchar = start_char + startt.endchar = start_char + endyield tprevend = match.end()# If the last "gap" was before the end of the text,# yield the last bit of text as a final token.if prevend < len(value):t.text = value[prevend:]t.boost = 1.0if keeporiginal:t.original = t.textt.stopped = Falseif positions:t.pos = posif chars:t.startchar = prevendt.endchar = len(value)yield tdef ChineseAnalyzer(expression=default_pattern, stoplist=None,minsize=2, maxsize=None, gaps=False, stemfn=stem,ignore=None, cachesize=50000):"""Composes a RegexTokenizer with a lower case filter, an optional stopfilter, and a stemming filter.用小写过滤器、可选的停止停用词过滤器和词干过滤器组成生成器。>>> ana = ChineseAnalyzer()>>> [token.text for token in ana("Testing is testing and testing")]["test", "test", "test"]:param expression: 用于提取 token 令牌的正则表达式:param stoplist: 一个停用词列表。 设置为 None 标识禁用停用词过滤功能。:param minsize: 单词最小长度,小于它的单词将被从流中删除。:param maxsize: 单词最大长度,大于它的单词将被从流中删除。:param gaps: 如果为 True, tokenizer 令牌解析器将会分割正则表达式,而非匹配正则表达式:param ignore: 一组忽略的单词。:param cachesize: 缓存词干词的最大数目。 这个数字越大,词干生成的速度就越快,但占用的内存就越多。使用 None 表示无缓存,使用 -1 表示无限缓存。"""ret = ChineseTokenizer(expression=expression, gaps=gaps)chain = ret | LowercaseFilter()if stoplist is not None:chain = chain | StopFilter(stoplist=stoplist, minsize=minsize,maxsize=maxsize)return chain | StemFilter(stemfn=stemfn, ignore=ignore,cachesize=cachesize)

重点是这个:
在这里插入图片描述
在PS2里面,结巴的大佬有提到有新功能(11年前的)jieba.cut_for_search()也可以试试

然后在whoosh_cn_backend.py里面修改ChineseAnalyzer

from .chinese_analyzer import ChineseAnalyzer
# from jieba.analyse import ChineseAnalyzer

PS:这个jieba自带的ChineseAnalyzer也是我换的,如果你第一次搞这个,可以参考

https://blog.csdn.net/qiqiyingse/article/details/110299639

PS

1.HayStack

As of version 2.4 the views in haystack.views.SearchView are
deprecated in favor of the new generic views in
haystack.generic_views.SearchView which use the standard Django
class-based views which are available in every version of Django which
is supported by Haystack.

在这里插入图片描述
新代码,旧流程,可真有你的。

2.CSDN

稍微吐槽下CSDN,STONE大哥的文章里面,下面结巴的大佬在评论区有回复,结果评论显示的是2条,还好我点开看了一下。不然就错过了这么重要的信息。

https://blog.csdn.net/wenxuansoft/article/details/8169842

在这里插入图片描述
然后显示的热评是个灌水回答。。
在这里插入图片描述
3.其他筛选参数
关于筛选的类型,在whoosh_cn_backend.py文件中,基本和django的差不多。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/74267.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++设计模式之过滤器设计模式

C过滤器设计模式 什么是过滤器设计模式 过滤器设计模式是一种行为型设计模式&#xff0c;它允许你在特定的条件下对输入或输出进行过滤&#xff0c;以便实现不同的功能。 该模式有什么优缺点 优点 可扩展性&#xff1a;过滤器设计模式允许您轻松地添加、删除或替换过滤器&a…

CVPR2023新作:源数据集对迁移学习性能的影响以及相应的解决方案

Title: A Data-Based Perspective on Transfer Learning (迁移学习的基于数据的观点) Affiliation: MIT (麻省理工学院) Authors: Saachi Jain, Hadi Salman, Alaa Khaddaj, Eric Wong, Sung Min Park, Aleksander Mądry Keywords: transfer learning, source dataset, dow…

iOS 应用上架的步骤和工具简介

APP开发助手是一款能够辅助iOS APP上架到App Store的工具&#xff0c;它解决了iOS APP上架流程繁琐且耗时的问题&#xff0c;帮助跨平台APP开发者顺利将应用上架到苹果应用商店。最重要的是&#xff0c;即使没有配置Mac苹果机&#xff0c;也可以使用该工具完成一系列操作&#…

算法39:Excel 表列序号

一、需求 给你一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如&#xff1a; A -> 1 B -> 2 C -> 3 … Z -> 26 AA -> 27 AB -> 28 … 示例 1&#xff1a; 输入: columnTitle “A” 输出: 1 示例 2&…

Minio在windows环境配置https访问

minio启动后&#xff0c;默认访问方式为http&#xff0c;但是有的时候我们的访问场景必须是https&#xff0c;浏览器有的会默认以https进行访问&#xff0c;这个时候就需要我们进行配置上的调整&#xff0c;将minio从http访问升级到https。而查看minio的官方文档&#xff0c;并…

配置IPv6 over IPv4手动隧道示例

组网需求 如图1所示&#xff0c;两台IPv6主机分别通过SwitchA和SwitchC与IPv4骨干网络连接&#xff0c;客户希望两台IPv6主机能通过IPv4骨干网互通。 图1 配置IPv6 over IPv4手动隧道组网图 配置思路 配置IPv6 over IPv4手动隧道的思路如下&#xff1a; 配置IPv4网络。配置接…

谁是全球最小ARM MCU?

先是从百度上查找的&#xff0c;找了半天&#xff0c;也找到了一部分。 大小基本在一二毫米左右&#xff0c;外设有多有少&#xff0c;但是好多都买不到货。 而且有些特别小众&#xff0c;开发环境压根没接触过。 然后去外面找了一下&#xff0c;竟然有好几个提到了HC32L110&am…

vue3和typescript_组件

1 components下新建myComponent.vue 2 页面中引入组件&#xff0c;传入值&#xff0c;并且绑定事件函数。 3

java+springboot+mysql企业邮件管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的企业邮件管理系统&#xff0c;系统包含超级管理员、管理员、员工角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;员工管理&#xff1b;反馈管理&#xff1b;系统公告&#xff1b;个人…

使用Git在GitHub上部署静态页面

在GitHub中&#xff0c;我们可以将自己的静态页面部署到GitHub中&#xff0c;它会给我们提供一个地址使得我们的页面变成一个真正的网站&#xff0c;可以供用户访问。 一、在GitHub下创建仓库 二、将项目部署到GitHub上 1. 初始化Git仓库 2. 提交代码 3. 关联远程仓库 在Gi…

PostgreSql 锁

一、概述 在 PostgreSQL 事务中提到&#xff0c;多个用户访问相同数据时可能出现脏读&#xff0c;不可重复度&#xff0c;幻读&#xff0c;更新丢失的问题&#xff0c;为解决这些问题&#xff0c;定义了不同的隔离级别&#xff0c;而隔离级别的具体实现&#xff0c;依靠的就是数…

开放自动化软件的硬件平台

自动化行业的产品主要以嵌入式系统为主&#xff0c;历来对产品硬件的可靠性和性能都提出很高的要求。最典型的产品要数PLC。PLC 要求满足体积小&#xff0c;实时性&#xff0c;可靠性&#xff0c;可扩展性强&#xff0c;环境要求高等特点。它们通常采用工业级高性能嵌入式SoC 实…

Django Rest_Framework(一)

1. Web应用模式 在开发Web应用中&#xff0c;有两种应用模式&#xff1a; 前后端不分离[客户端看到的内容和所有界面效果都是由服务端提供出来的。] 前后端分离【把前端的界面效果(html&#xff0c;css&#xff0c;js分离到另一个服务端或另一个目录下&#xff0c;python服务…

使用 github 同步谷歌浏览器书签

想必使用谷歌浏览器Chrome的用户一定非常头疼的一件事就是&#xff1a;账户不能登录&#xff0c;书签收藏夹不能同步&#xff0c;换一台电脑书签收藏夹没有了&#xff01; 下面教大家一招亲测有效适用的方法解决书签同步问题&#xff0c;在任何电脑都可以同步了 1、去下载谷歌…

从零开始学Docker(三):DockerFile镜像定制

宿主机环境&#xff1a;RockyLinux 9 前言&#xff0c;定制docker镜像的方式有两种&#xff1a; 手动修改容器内容&#xff0c;然后docker commit提交容器为新的镜像通过在dockerfile中定义一系列的命令和参数构成的脚本&#xff0c;然后这些命令应用于基础镜像&#xff0c;依…

websocket服务端大报文发送连接自动断开分析

概述 当前springboot版本&#xff1a;2.7.4 使用依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency>现象概述&#xff1a; 客户端和服务端已经有心跳…

iframe跨域解决方案

在 Web 开发中&#xff0c;跨域是指在一个域&#xff08;例如&#xff0c;https://www.example.com&#xff09;的页面中请求了另一个域&#xff08;例如&#xff0c;https://api.example.com&#xff09;的资源&#xff0c;浏览器出于安全考虑会阻止这样的请求。为了解决 ifra…

Jmeter如何添加插件

一、前言 ​ 在我们的工作中&#xff0c;我们可以利用一些插件来帮助我们更好的进行性能测试。今天我们来介绍下Jmeter怎么添加插件&#xff1f; 2023最新Jmeter接口测试从入门到精通&#xff08;全套项目实战教程&#xff09; 二、插件管理器 ​ 首先我们需要下载插件管理器j…

机器学习 | Python实现NARX模型预测控制

机器学习 | Python实现NARX模型预测控制 目录 机器学习 | Python实现NARX模型预测控制效果一览基本介绍研究内容程序设计参考资料效果一览 基本介绍 机器学习 | Python实现NARX模型预测控制 研究内容 贝叶斯黑盒模型预测控制,基于具有外源输入的非线性自回归模型的预期自由能最…

地址空间细致入微+深入了解页表

目录 地址空间保存了什么&#xff1f; 页表到底是怎么存储的 我们都知道&#xff0c;我们进程看到的空间其实是虚拟内存&#xff0c;真正的内存是需要页表的映射才能找到真正的物理内存&#xff0c;那么我我们有两个问题的引出那么进程地址空间是保存了什么呢&#xff1f;页表…