今天来给大家聊聊,针对一些简单的分词的解决方案。

首先我们来看一个常用的场景:

一个购物网站的搜索功能,要求可以根据用户的搜索精准的查询到商品,比如我要买咖啡,我搜索关键字 咖啡 可以搜索到很多咖啡商品,但我要求搜索 我要买好喝的咖啡 也可以搜索到很多咖啡商品。这要如何实现呢?

对于仅仅搜索关键字来说,小库直接去like查询,就可以解决,若库大了做索引,缓存等都可以去解决,这里就不再赘述了,因为我们今天主要的核心讨论点是分词

我们来看这句话 我要买好喝的咖啡 ,通过我们自主的观察,我们需要的是 咖啡,其是一个名词,而去除掉 我 买 是一个动词, 好喝 是一个形容词。这样我们就捋清楚了,我们其实大部分搜索需要的都是名词。

这样我们只要能从 我要买好喝的咖啡 中通过分词,顺利找到 咖啡 ,或者说,从一段需要搜索的话中,找到其中的所有名词,就可以了。

今天给大家推荐的分词工具包,是由清华大学自然语言处理与社会人文计算实验室研制推出的一套中文词法分析工具包,其官网(http://thulac.thunlp.org/)的描述是这样的:

THULAC(THU Lexical Analyzer for Chinese)由清华大学自然语言处理与社会人文计算实验室研制推出的一套中文词法分析工具包,具有中文分词和词性标注功能。THULAC具有如下几个特点:

  1. 能力强。利用我们集成的目前世界上规模最大的人工分词和词性标注中文语料库(约含5800万字)训练而成,模型标注能力强大。
  2. 准确率高。该工具包在标准数据集Chinese Treebank(CTB5)上分词的F1值可达97.3%,词性标注的F1值可达到92.9%,与该数据集上最好方法效果相当。
  3. 速度较快。同时进行分词和词性标注速度为300KB/s,每秒可处理约15万字。只进行分词速度可达到1.3MB/s。

目前,其提供了C++、Java和Python的包供大家使用,那么对于其他语言的人怎么办呢?

其实很简单,只要用这三种语言,写个端口和地址监听,提供一个分词的API接口就行了,有人会问了,这三种语言不会啊,环境都不会配,怎么办?

不要忘记了,我们有 Docker !!!

我选用Python来构建一个API接口,通过使用thulac的包,然后我选用flask(http://www.pythondoc.com/Flask-RESTful/)来写个简单的接口文件,然后在一个有Python环境下,运行监听地址和端口,其他语言只要去访问这个接口,就可以获取到针对句子的分词结果了,然后根据自己的业务逻辑,对分词结果做相应的处理,就可以了。

我们先来完成接口文件

import thulac
import json
from flask_restful import Api, Resource
from flask import Flask, request

thul = thulac.thulac(filt=True);
app = Flask(__name__);
api = Api(app);

history = {};
index = 0;
class CutWord(Resource):
def get(self):
return history;

def post(self):
global index;
req = request.form['data'];
res = thul.cut(req);
history[index] = {'req': req, 'res': res};
index = index + 1;
return res;

api.add_resource(CutWord, '/');
if __name__ == '__main__':
app.run(host='0.0.0.0');

上面我监听了本地的5000端口(FLask默认5000端口),对根路径提供RESTful接口,其针对get获取历史查询列表,对post将会通过data提供的句子做分词并返回结果。当然这只是一个简单的接口,有兴趣的Python大神们可以扩展出更多的功能和做性能优化等。

然后我们需要的仅仅是一个环境了。环境已经给大家配好了,只需要以下几条命令

docker pull jarod2014/thulac-flask

附上Dockerfile

FROM python:alpine

MAINTAINER xinghen249@gmail.com

RUN pip install thulac
RUN pip install flask
RUN pip install flask-restful

这样,我们新建一个镜像,并通过运行接口提供服务就可以了,假设我们的API脚本路径为/app/python/api.py

docker run -d --name cutwordsapi --restart=always -v /app/python:/www jarod2014/thulac-flask python /www/api.py

这样,镜像就建立完成了,假设我们有一个phpfpm的镜像,我们先需要使用–link cutwordsapi:cutwordsapi 来做一个链接,这样就不会因为启动顺序造成Docker镜像的IP不同出问题了

docker run -d --name phpfpm xxxxxxx --link cutwordsapi:cutwordsapi  xxxxxxx

这样,两个镜像就链接起来了

下面我们来在php镜像中,运行一个测试脚本,脚本如下

$statement = "我想买好喝的咖啡";

$ch = curl_init("cutwordsapi");

curl_setopt($ch, CURLOPT_PORT, 5000);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

curl_setopt($ch, CURLOPT_POST, 1);

curl_setopt($ch, CURLOPT_TIMEOUT, 5);

curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([

"data" => $statement

]));

$res = curl_exec($ch);

curl_close($ch);

var_dump(json_decode($res, true));

我们可以看到,接口返回了数组

[
[“想”, “v”],
[“买”, “v”],
[“好”, “a”],
[“喝”, “v”],
[“咖啡”, “n”]
]
这样我们遍历数组,通过每个词性做识别,就可以找到句子中的名词,再通过名字去库里查询就可以了。
好了,今天就到这里吧,下面发两张应用此方法的搜索截图。