编者注:我们发现了有趣的一系列文章《30天学习30种新技术》,正在翻译中,一天一篇更新,年终礼包。下面是第 14 天的内容。
我并不是一个机器学习(Machine Learning)、自然语言处理(Natural Text Processing,NLP)等的*者,但我总会想到一些需要用到它们的主意。我们今天在这篇博文中要实现的目标是:利用 Twitter 数据建立一个实时的职位搜索。每个单独的搜索结果要包括提供职位的公司名称、工作的地点、去公司应聘时联系的人。这需要我们从 个人(Person)、地点(Location)、组织(Organisation)三方面去分析每一条推(tweet)。这类问题被归为命名实体识别(Named Entity Recognition,NER)问题。
根据*的资料,命名实体识别是信息提取(Information Extraction)的一个子任务,它把文字的原子元素(Atomic Element)定位和分类好,然后输出为固定格式的目录,例如: 人名、组织、位置、时间的表示、数量、货币值、百分比等。
为了说的更明白,我们来举个例子。假设我们有下面这条推:
一个普通人可以轻易地分辨出一个名为 PSI Pax 的组织在 Baltimore 有个空缺的职位。但是我们怎么用编程的方式来完成这个识别呢? 最简单的办法是维护一个包含所有组织名称、地点的列表,然后对这个列表进行搜索。然而,这种做法的可扩展性太差了。
今天,在这篇博文中,我会描述如何用斯坦福 NER(Stanford NER) 软件包去设置我们自己的 NER 服务器。
什么是 斯坦福 NER?
斯坦福 NER 命名实体识别(Named Entity Recognizer,NER)的 Java 实现。 NER 标识一段文字中的一系列名词,例如人名、公司名,又或者基因名、蛋白质名。
前期准备
-
一些基本的 Java 知识是需要的。在你的操作系统上安装最新版本的 JDK,你可以安装 OpenJDK 或者 Oracle JDK 7。OpenShift 支持 OpenJDK 6 和 7.
-
从官网中下载斯坦福 NER 软件包。
-
注册一个 OpenShift 账户。这是完全免费的,而且红帽(Red Hat)会给每个用户三个免费的 Gears,在 Gears 上你可以运行你的程序。在这篇文章写的时候,OpenShift 会为每个用户分配 1.5GB 的内存和 3GB 的硬盘空间。
-
在本机上,安装 rhc 客户端工具。rhc 是一个 ruby gem,所以你需要机子上安装好 ruby 1.8.7 及以上的 ruby。要安装 rhc,输入:
sudo gem install rhc
更新 rhc 到最新版本,执行:
sudo gem updatge rhc
如果需要阅读额外的安装 rhc 命令行工具时的帮助文件,可以浏览:https://openshift.redhat.com/community/developers/rhc-client-tools-install
5.使用 rhc setup 命令设置好 OpenShift 账户,这个命令会为你创建一个命名空间,然后上传你的 ssh keys 到 OpenShift 服务器上。
第一步:创建一个 JBoss EAP 应用
我们现在开始创建这个演示应用。这个应用的名称是 nerdemo
rhc create-app nerdemo jbosseap
如果你可以访问媒介齿轮(Medium Gears),你可以使用下面的命令:
$ rhc create-app nerdemo jbosseap -g medium
它会为我们创建一个应用容器,叫做 Gear,会自动设置好需要的 SELinux/cgroup 配置。OpenShift 也会为我们建立一个私密的 git 仓库,然后可克隆这个仓库到本地系统上。最后,OpenShift 还会部署一个连接外面的 DNS。部署的应用可以通过链接: http://linkbin-domain-name.rhcloud.com/ 来访问。把领域换成自己的 OpenShit 领域(有时候叫 命令空间)
第二步:增加 Maven 依赖
在 pom.xml 文件中,增加一下依赖:
<dependency>
<groupId>edu.stanford.nlpgroupId>
<artifactId>stanford-corenlpartifactId>
<version>3.2.0version>
dependency>
然后,通过更新 pom.xml 文件中的一些属性把 Maven 项目更新到 Java 7
compiler.source>1.7compiler.source>
compiler.target>1.7compiler.target>
现在,通过 右击 > Maven > 更新项目
更新 Maven
第三步:开启 CDI
我们会使用 CDI 来进行依赖项注入(Dependency Injection)。CDI(Context and Dependency Injection)是 Java EE 6 的一个特性,它允许在 Java EE 6 项目中的依赖项注入。CDI 为 Java EE 定义一个类型安全(type-safe) 的 依赖项注入机制。几乎任何 POJO 可以作为 CDI 豆(bean)那样被注入。
在 src/main/webapp/WEB-INF 目录下,创建一个名为 beans.xml 的 xml 文件。用下面的内容代替 beans.xml 的内容:
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
beans>
第四步:应用程序作用域分类器的豆(Application Scoped Classifier Bean)
现在,我们创建一个应用程序作用域的豆(bean),这个豆会创建 CRFClassifier 类的实例。这个分类器用于检测文字中的名字、地点和组织
package com.nerdemo;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Named;
import edu.stanford.nlp.ie.crf.CRFClassifier;
import edu.stanford.nlp.ling.CoreLabel;
@ApplicationScoped
public class ClassifierConfig {
private String serializedClassifier = "classifiers/english.all.3class.distsim.crf.ser.gz";
private CRFClassifier<CoreLabel> classifier;
@PostConstruct
public void postConstruct() {
CRFClassifier<CoreLabel> classifier = CRFClassifier.getClassifierNoExceptions(serializedClassifier);
this.classifier = classifier;
}
@Produces
@Named
public CRFClassifier<CoreLabel> classifier() {
return classifier;
}
}
从下载的斯坦福 NER 软件包中复制 english.all.3class.distsim.crf.ser.gz 分类器到 src/main/resources/classifiers 目录下。
第五步:开启 AX-RS
为了开启 AX-RS,创建一个扩展 javax.ws.rs.core.Application 的类,然后用下面 javax.ws.rs.ApplicationPath 的标记法标记应用程序的路径:
package com.nerdemo;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/api/v1")
public class JaxrsInitializer extends Application{
}
第六步:创建 ClassifyRestResource 类
现在我们要创建 ClassifyRestResource 类,它返回一个 NER 结果。创建一个新的 ClassifyRestResource 类,然后用下面代码代替它:
package com.nerdemo;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import edu.stanford.nlp.ie.crf.CRFClassifier;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.ling.CoreLabel;
@Path("/classify")
public class ClassifierRestResource {
@Inject
private CRFClassifier classifier;
@GET
@Path(value = "/{text}")
@Produces(value = MediaType.APPLICATION_JSON)
public List findNer(@PathParam("text") String text) {
List> classify = classifier.classify(text);
List results = new ArrayList<>();
for (List coreLabels : classify) {
for (CoreLabel coreLabel : coreLabels) {
String word = coreLabel.word();
String answer = coreLabel.get(CoreAnnotations.AnswerAnnotation.class);
if(!"O".equals(answer)){
results.add(new Result(word, answer));
}
}
}
return results;
}
}
部署到 OpenShift
最后,部署所做的改变到 OpenShift:
$ git add .
$ git commit -am "NER demo app"
$ git push
当代码成功部署之后,我们可以通过访问 http://nerdemo-{domain-name}.rhcloud.com 看到应用运行。我的示例应用运行在: http://nerdemo-t20.rhcloud.com
然后,你就会得到一个 JSON 格式的结果:
[
{"word":"Microsoft","answer":"ORGANIZATION"},
{"word":"PSI","answer":"ORGANIZATION"},
{"word":"Pax","answer":"ORGANIZATION"},
{"word":"Baltimore","answer":"LOCATION"}
]
这就是今天的内容了,保持反馈!
接下来
- 在线登录 OpenShift 帐号
- 通过评估 OpenShift 企业版获得自己的私有 PaaS(Platform As a Service)。
- 需要帮助? 去 OpenShift Community 论坛问问题。
- 在 OpenShift Developer Spotlight 中展示你的酷应用。今天就开始浏览下OpenShift 应用展览