Django-Haystack 全文检索之highlight 标签和自定义Highlighter

本文介绍了Django-Haystack中highlight标签的使用,详细阐述了其工作逻辑,指出了默认highlight标签存在的问题,尤其是在query位于文本末尾时的不友好显示。为解决这一问题,文章探讨了自定义Highlighter的方法,包括重写`find_window`方法以优化搜索结果的显示。读者将了解到如何通过继承Highlighter类并调整设置来改善全文检索的高亮体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Django-Haystack 全文检索之highlight 标签和自定义Highlighter

highlight在全文检索起到的作用是:用户在浏览器,搜索关键字,服务器返回相关结果,然后haystack把该关键字高亮起来的过程。

在这里插入图片描述

haystack highlight 标签的用法

{% highlight <text_block> with <query> [css_class "class_name"] [html_tag "span"] [max_length 200] %}

实例

{% highlight result.summary with query max_length 40 css_class "my_css_class"%}

highlight-标签名
text_block-用户显示的文本,通常为model.attr
query-关键字
css_class-显示的样式 - 用户自己的css文件
html_tag-使用哪个HTML标签,默认是span
max_length-返回的文本最大长度(含高亮的搜索词)

highlight 标签的实现逻辑

用户在浏览器,搜索关键字,服务器返回结果,并把该关键字高亮起来

前端使用到了highlight标签,所以haystack会调用haystack\templatestags\highlight.py 里的hightlight方法(被haystack注册成标签) 该方法返回的是一个HighlightNode对象

def highlight(parser, token):
    ...
    这部分代码的作用是拆分模板里的 {% highlight result.summary with query max_length 40 css_class "my_css_class"%} 标签代码
    text_block: result.summary
    css_class: my_css_class 定义在css文件里
    html_tag: 最终展示搜索词的HTML标签, 默认是span
    ...
    ...
    ...
    # kwargs字典分别有:kwargs['css_class']
    # kwargs['html_tag']
    # kwargs['max_length']
    return HighlightNode(text_block, query, **kwargs)

HighlightNode的render()方法会被调用(还没看实现代码),然后通过haystack\templatestags\highlighting.py Highlighter类的highlight() 方法获得highlighted_text, 然后返回highlighted_text。

而这个highlighted_text,就是我们前端看到的高亮效果的HTML。highlighted_text如下图所示。

class HighlightNode(template.Node):
	def render(self, context):
		 ...
         ...
         ...
         这时候这个方法会去找一下setting.py文件是否有用户自定义的Highlighter类,如果有就使用用户的否则就使用默认的Highlighter
         if hasattr(settings, 'HAYSTACK_CUSTOM_HIGHLIGHTER') and settings.HAYSTACK_CUSTOM_HIGHLIGHTER:    
         ...
         highlighter = highlighter_class(query, **kwargs)  # highlighter_class的赋值是,到底使用哪个Highlighter类,默认使用haystack\templatestags\highlight.py的Highlighter类
         highlighted_text = highlighter.highlight(text_block) # 调用highlight方法,获得highlighted_text

         return highlighted_text # 如上图所示,format类似:plain text +<span class="my_css_class">query</span> + plain text
       
class Highlighter(object):
        def highlight(self, text_block):
        self.text_block = strip_tags(text_block)  # 过滤HTML标签
        highlight_locations = self.find_highlightable_words()  # 找到需要高亮的搜索词query处于整个文本(在这个例子里是 result.summary)的位置offset, format: [(0, "your_query"), (14, "your_query")]
        start_offset, end_offset = self.find_window(highlight_locations)  # 由于用户给定了搜索结果的max_length,言下之意,搜索的结果长度小于等于result.summary的长度,所以需要找到在既定长度
                                                                          # 也就是max_length下,result.summary的什么区间存在最多的query,然后返回该区间的起止位置, 这里有个不太满足需求的地方,
                                                                          # 下面会带出
        return self.render_html(highlight_locations, start_offset, end_offset) # 在获得需要高亮的结果的位置,搜索结果起止位置,然后组装html文本

highlight tag的不足

Django提供的{% highlight %} 标签, 可以达到高亮query的效果。 但同时,也存在其不足。当query 为单个查询关键词的时候, haystack返回的文本是从找到该关键词为起点start_offset, 到start_offset+max_length。

但当这个query,处于整个搜索文本的最末尾的时候, 返回结果是“…”+query(示例如下)。( "…"是在Highlighter的render_html()里添加的 ) 这样的结果显示相当不友好。效果如下图。

haystack\templatestags\highlighting.py Highlighter类的find_window()方法

 if len(words_found) == 1:
     return (words_found[0], words_found[0] + self.max_length)

在这里插入图片描述

自定义Highlighter

所以在理解highlight标签实现的过程后,个人的做法是继承Highlighter类,然后重写find_window方法。因为find_window决定了搜索结果处于整个文本result.summary的区间(起止位置 )。

util.py

from haystack.utils import Highlighter 

class MyHighLighter(Highlighter):            
    def find_window(self, highlight_locations):
    	...
    	...
    	# 只修改了if len(words_found) == 1 的代码段
    	if len(words_found) == 1:
            # return (words_found[0], words_found[0] + self.max_length)  #  
            # new added
            best_start = words_found[0]
            best_end = words_found[0] + self.max_length

            if best_end > len(self.text_block):
                current_length = len(self.text_block) - best_start
                move_forward_steps = self.max_length - current_length
                best_start = best_start - move_forward_steps
                # 逻辑如下图, 实现的方式各有不同,按自己理解和需求就好
                # 这里的逻辑是因为搜索词query处于text_block的末尾,所以用max_length-query的长度=剩下的长度(move_forward_steps)

                if best_start < 0:
                    best_start = 0
            return (best_start, best_end)

在这里插入图片描述

setting.py

HAYSTACK_CUSTOM_HIGHLIGHTER = "你的路径.utils.MyHighLighter"

xxx.html

{%  load highlight %}
{% highlight goods.object.g_title with query max_length 16 css_class "highlight"%}

xxx.css

/*for highlight*/
.highlight{color:red;}

到此,自定义的highlighter类就修改好了。

![在这里插入图片描述](https://img-blog.csdnimg.cn/20190615002421621.?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI0OTg5MjI=,size_16,color_FFFFFF,t_70

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值