Watson Conversation には System Entity として日付、時刻、数値、通貨をテキストから抽出する機能があるので、それに特化して利用する。
利用するライブラリは watson Java SDK
https://github.com/watson-developer-cloud/java-sdk
概要
入力:"平成30年4月1日です。"
出力:
EntityKeyword [facet=sys-date, begin=0, end=9, lex=2018-04-01, str=平成30年4月1日]
EntityKeyword [facet=sys-number, begin=2, end=4, lex=30, str=30]
EntityKeyword [facet=sys-number, begin=5, end=6, lex=4, str=4]
EntityKeyword [facet=sys-number, begin=7, end=8, lex=1, str=1]
SDK のライブラリを以下のようにWrapして使う。
サービス本体
package com.ibm.watson.developer_cloud.conversation;
import java.util.*;
import com.ibm.watson.developer_cloud.conversation.v1.ConversationService;
import com.ibm.watson.developer_cloud.conversation.v1.model.Entity;
import com.ibm.watson.developer_cloud.conversation.v1.model.MessageRequest;
import com.ibm.watson.developer_cloud.conversation.v1.model.MessageResponse;
public class ConversationNLPService {
String username;
String password;
String workspaceid;
public ConversationNLPService(String username, String password, String workspaceid) {
this.username = username;
this.password = password;
this.workspaceid = workspaceid;
}
public ConversationNLPServiceResponse nlp(String input) throws Exception {
ConversationService service = new ConversationService(ConversationService.VERSION_DATE_2016_09_20);
service.setUsernameAndPassword(username, password);
Map<String, Object> context = new HashMap<String, Object>();
{
// SET TIMEZONE
context.put("timezone", TimeZone.getDefault().getID());
}
// remove control code
input = input.replace("\t", " ").replace("\n", " ").replace("\r", " ");
MessageRequest newMessage = new MessageRequest.Builder() //
.inputText(input) //
.context(context) //
.build();
MessageResponse response = service.message(workspaceid, newMessage).execute();
String s = response.getInputText();
ConversationNLPServiceResponse rsp = new ConversationNLPServiceResponse();
List<Entity> list = response.getEntities();
for (Entity e : list) {
EntityKeyword kwd = new EntityKeyword(e.getEntity(), e.getLocation()[0], e.getLocation()[1], e.getValue(),
s.substring(e.getLocation()[0], e.getLocation()[1]));
rsp.addKeyword(kwd);
}
return rsp;
}
}
package com.ibm.watson.developer_cloud.conversation;
import java.util.ArrayList;
public class ConversationNLPServiceResponse {
ArrayList<EntityKeyword> kwds = new ArrayList<>();
protected void addKeyword(EntityKeyword kwd) {
for (EntityKeyword kw : kwds) {
if (kw.getFacet().equals(kwd.getFacet()) && kw.isLongerMach(kwd)) {
System.err.println("!! " + kwd);
return;
}
}
this.kwds.add(kwd);
}
public ArrayList<EntityKeyword> asList() {
return kwds;
}
}
package com.ibm.watson.developer_cloud.conversation;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class EntityKeyword {
public static String SYS_DATE = "sys-date";
public static String SYS_NUMBER = "sys-number";
public static String SYS_CURRENCY = "sys-currency";
String facet;
int begin;
int end;
String lex;
String str;
static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public boolean isLongerMach(EntityKeyword kwd) {
return (this.begin <= kwd.begin) && (kwd.end <= this.end) && ((kwd.end - kwd.begin) < (this.end - this.begin));
}
public Date asDate() {
if (isDate() == false) {
return null;
} else {
try {
return sdf.parse(this.lex);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
}
public boolean isDate() {
return facet != null && facet.equals(SYS_DATE);
}
public boolean isCurrency() {
return facet != null && facet.equals(SYS_CURRENCY);
}
public boolean isNumber() {
return facet != null && facet.equals(SYS_NUMBER);
}
public EntityKeyword(String facet, int begin, int end, String lex, String str) {
super();
this.facet = facet;
this.begin = begin;
this.end = end;
this.lex = lex;
this.str = str;
}
public int getBegin() {
return begin;
}
public int getEnd() {
return end;
}
public String getLex() {
return lex;
}
public String getFacet() {
return facet;
}
public String getStr() {
return str;
}
@Override
public String toString() {
return "EntityKeyword [facet=" + facet + ", begin=" + begin + ", end=" + end + ", lex=" + lex + ", str=" + str
+ "]";
}
}
使い方
package com.ibm.watson.developer_cloud.conversation;
import java.util.ArrayList;
public class ConversationNLPServiceMain {
public static void main(String[] args) throws Exception {
// PLEASE GET credentials from https://console.bluemix.net/home/
// Enablement_Conversation
String username = "xxx";
String password = "xxx";
// CONV_NLP
String workspaceid = "xxx";
ConversationNLPService service = new ConversationNLPService(username, password, workspaceid);
String input = "平成30年4月1日です。";
ConversationNLPServiceResponse response = service.nlp(input);
ArrayList<EntityKeyword> kwds = response.asList();
for (EntityKeyword kwd : kwds) {
System.err.println(kwd.toString());
}
}
}
EntityKeyword [facet=sys-date, begin=0, end=9, lex=2018-04-01, str=平成30年4月1日]
EntityKeyword [facet=sys-number, begin=2, end=4, lex=30, str=30]
EntityKeyword [facet=sys-number, begin=5, end=6, lex=4, str=4]
EntityKeyword [facet=sys-number, begin=7, end=8, lex=1, str=1]
だいたいこんな感じ...
「平成30年4月1日」が「2018-04-01」に正規化されます。
「明日」とか「来週の日曜」でも正規化できます。
ただし、間違いもあるので過度に依存しないようにする必要はあると思います。
このクラスを改造して「結果の中に日付が1つだけの場合の処理」「日付と時刻が連続している場合の扱い」などを追加するとよいと思います。
Watson API に NLP系のAPIもあってよいと思いますが、なぜか提供されていないのでこのようなものを作ってみました。