python實如今線分詞

寫在前面

最近在優化網站的搜索部分,網站是用Django實現的,主要業務是在線視頻教育網站,以前搜索只是一段Django ORM模型中的icontains模糊匹配,因此只能搜索關鍵字,可是CEO(SB)忽然又想在網站作個相似於百度問答的功能。可是搜索問題就成了一個棘手的事情,原有搜索不能知足需求,可是調研相關的elasticsearch之類的全文檢索又有點重(除了有點重,主要是CEO不給時間啊!),因此就把精力放在了分詞上,能短平快的實現該功能,並且比較輕。html

由於關注的梁博,天然而然想到了他博士期間寫的在線分詞pullword(寫這篇文章時他我的網站又掛掉了,哈哈哈,這裏貼出了他的微博供你們膜拜),在此對梁博表示感謝!!python

下面是我寫的分詞的utils,不過樑博的分詞如今只能支持中文,輸入英文跟數字會返回error,以前是想調用梁博的原有的pullword,他的API地址,可是我測了一下須要6-7秒,對於網站搜索功能顯然沒辦法使用,後來又找到他掛在百度的免費API,測試了一下數據返回在0.1秒左右,還不錯,就使用了百度api。後端

要注意,他原生的api中有個param1的參數,表示選詞機率,param1=0.8表示只出機率在0.8以上的詞,可是我調用傳參的時候很差用,因此就經過返回的數據本身寫了篩選。
get_pullword須要兩個參數,第一個是一段須要分詞的話,第二個是篩選分詞後選詞機率,[0,1]區間,等同於他的param1的參數。api

圖片描述

# 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處理的方法。app

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實現簡單分詞就寫完了。elasticsearch

相關文章
相關標籤/搜索