写在前面
最近在优化网站的搜索部分,网站是用Django实现的,主要业务是在线视频教育网站,之前搜索只是一段Django ORM模型中的icontains
模糊匹配,所以只能搜索关键字,但是CEO(SB
)突然又想在网站做个类似于百度问答的功能。但是搜索问题就成了一个棘手的事情,原有搜索不能满足需求,但是调研相关的elasticsearch之类的全文检索又有点重(除了有点重,主要是CEO不给时间啊!),所以就把精力放在了分词上,能短平快的实现该功能,而且比较轻。
因为关注的梁博,自然而然想到了他博士期间写的在线分词pullword(写这篇文章时他个人网站又挂掉了,哈哈哈,这里贴出了他的微博供大家膜拜),在此对梁博表示感谢!!
下面是我写的分词的utils,不过梁博的分词现在只能支持中文,输入英文跟数字会返回error,之前是想调用梁博的原有的pullword,他的API地址,但是我测了一下需要6-7秒,对于网站搜索功能显然没办法使用,后来又找到他挂在百度的免费API,测试了一下数据返回在0.1秒左右,还不错,就使用了百度api。
要注意,他原生的api中有个param1的参数,表示选词概率,param1=0.8表示只出概率在0.8以上的词,但是我调用传参的时候不好用,所以就通过返回的数据自己写了筛选。get_pullword
需要两个参数,第一个是一段需要分词的话,第二个是筛选分词后选词概率,[0,1]区间,等同于他的param1的参数。
# coding: utf-8
__author__ = 'flyingpang'
import requests
import datetime
def get_pullword(s, probability):
"""
:param s: 一段需要分词的中文.
:param probability: 选词概率.
:return: 按照概率从大到小排序返回一个list.
"""
headers = {'apikey': '你自己的百度apikey'}
url = 'http://apis.baidu.com/apistore/pullword/words'
params = {'source': s, 'param1': '0', 'param2': '1'}
r = requests.get(url=url, headers=headers, params=params)
if r.status_code != 200 or r.content.strip().split('\r\n')[0].startswith('error'):
result = list()
result.append(s)
return result
else:
data = r.content.strip().split('\r\n')
return split_word(data, probability)
def split_word(words, probability=0):
"""
:param words: 分词结果的字典, 其中key为分词,value为概率.
:param probability: 最小分词概率
:return: 概率从大到小的分词列表.
"""
# 分词跟相关概率保存到字典中.
d = dict()
for i in words:
m = i.split(':')
d[m[0].decode('utf-8')] = float(m[1])
m = sorted(d.iteritems(), key=lambda k: k[1], reverse=True)
words_list = []
for i in range(len(m)):
if m[i][1] >= probability:
words_list.append(m[i][0])
return words_list
if __name__ == '__main__':
source = u'清华大学是好学校'
t1 = datetime.datetime.now()
test = get_pullword(source, 0.8)
t2 = datetime.datetime.now()
print "total time", t2 - t1
print test
因为我后端使用Diango的icontains来匹配,所以返回一个list的话没办法匹配,所以这里给出一个Django处理的方法。
query = self.request.GET.get("q", None)
pull_words = get_pullword(query, 0.8) # 筛选出大于0.8概率的词
query_list = reduce(operator.or_, (Q(title__icontains=item) for item in pull_words))
question_list = Question.objects.filter(query_list).order_by("-id")
至此python实现简单分词就写完了。