最近做项目使用了whoosh+flask,因为flask使用的是jinjia2 模板引擎,所以就此遇到的html转义的问题做一个解释.
以上为背景.
使用whoosh+falsk搜索的时候,我采用的是关键词高亮显示,但是在实际操作的过程中,生成的html是带<b></b>标签的字符串,无论怎样,这个标签字符串总是显示在html页面中.
开始我以为是因为在输出的过程中转义有问题,所以搜索python的html转义方法.无论正转义还是反转义,结果都不行.
开始后来渐渐怀疑到jinjia2模板引擎上面,我从一开始已未需要加参数 “|e” 调试仍然不行,后来继续搜close escape html 才发现有一个safe参数,能够保证原始的 string 就不会被escape,修改后
{{ row.hit_title|safe }}
从whoosh的坑里爬出来了,简单介绍一下实用搜索方面的内容,之前绕路了,希望以后学习的人不会绕远路.既然讲的话,就从我的一路的坑细细数来吧.
首先是受到whoosh官方demo的影响,我以为只能使用关键词的搜索,所以我用的如下方法:
for keyword in ("水果世博园", "你", "first", "中文", "交换机", "交换"): print("result of ", keyword) q = parser.parse(keyword) results = searcher.search(q) for hit in results: # print(hit.highlights("content")) print(hit)
当然这样的话搜索出来的结果都是每个关键词对应的一个搜索列表.这时候我甚至一度怀疑whoosh不支持短语的搜索,因为害怕自己去写搜索算法,于是此事搁置.
今天早上忽然有想到这个问题了,继续搜相关内容,无意中看到csdn上面有一篇文章提到Or Term And这种关键词,终于又回到whoosh手册上面了…真的是想要学一门技术就去读它的手册,上次吃亏在scrapy的logging上面…
然后开始进行程序改造,搜索短语,比如搜索:”中国国际物流节开幕”,采用结巴分词,先把这句话分解成一个个的关键词.
inputstring = "中国国际物流节开幕" keywords = [] for t in analyzer(inputstring): keywords.append(t.text)
拆开的关键词是:中国 国际 物流 国际物流节(我自己添加到jieba字典里面的) 开幕
然后采用各种手册上面的iter_all_terms terms方法,不行,然后继续看手册,发现其实parse默认的标准是采用的And,而且我搜索的字段是body,而这句话是我从title里面复制出来的,自然返回为空了.
知道了基本原理就先通过修改Term进行测试:
And([Term("title", "中国"), Term("title", "国际"), Term("title", "物流"), Term("title", "国际物流节"), Term("title", "开幕")])
通过该And和Or来调解Trem去测试搜索结果,总体来看基本思路是对的.
Or([Term("title", "中国"), Term("title", "国际"), Term("title", "物流"), Term("title", "国际物流节"), Term("title", "开幕")])
通过上面的querystring 终于搜索出来结果了…
那么既然结果出来了,下一步就是继续给搜索添加条件了,类似谷歌的搜索是如何做到的呢?于是我再google上面搜索”whoosh like search google”
然后在stackoverflow上面搜索出来答案了,给出的几个选择pyl,pyprasing等…然后继续搜索whoosh和pyprasing,搜索出来的代码都是在whoosh,support.pyprasing下面调用的,我import没有啊,继续看搜索结果,,,看到whoosh里面有这么一句话:(In previous versions of Whoosh, the query parser was based on pyparsing. The new hand-written parser is less brittle and more flexible.)
你说什么!whoosh原本就是基于pyparsing构造语法的?往下看手册,,,真的是必须硬着头皮看手册啊….
发现whoosh本身支持通过” “(空格)来分割关键词搜索的.也是支持and or 这种直接的搜索语法的,还可以自己定义这些逻辑符号.
再往下就顺利多了,随便贴一点我用到的关键代码把:
inputstring = "中国and(国际or物流)and开幕"
qp = MultifieldParser(["title", "body"], schema=ix.schema)
querystring = qp.parse(inputstring) results = searcher.search(querystring, terms=True, limit=100, collapse_limit=1) for hit in results: print(hit['title'].encode('gbk'))
RTFM!
RTFM!
RTFM!