どっちの辞書？ ～WEXの辞書構築において「ユーザー辞書」と「パターン」を比較してみる～

#概要

WEX（IBM Watson Explorer Analytical Components）でテキストマイニングする際に、分析対象の文書が業界に特化していて、製品番号や業界用語などの正確なアノテーションが求められる場合があります。
各言語における標準的な辞書もデフォルトで実装されていますが、精度高く抽出するのには専用のカスタム辞書の構築が必要です。WEXでは、「ユーザー辞書」と「パターン」の２つの方法があります。
ここでは英語文章の解析を前提にこの２つの辞書構築を比較してみます。
※ 環境は以下を使用：
Watson Explorer Analytical Components v11.0.2 Linux版

#辞書運用で実現したい要件

英語の文書においてアノテーションを効率的・効果的に行うための辞書の要件としては、以下のようなものがあります．

(1) 自然文中に現れる用語の表記の次のような「揺らぎ」に対応できること
　1. 名詞の複数形の変化
　2. 動詞の三人称・時制などの語形変化
　3. 文頭や専門用語における大文字小文字の変化
　4. ハイフン、アンダースコアや特殊記号
　5. 複数の語句からなる複合語（慣用句など含む）語の抽出
(2) 多くの用語を一括で登録・管理できること

WEXのユーザー辞書とパターンの２つの方法は、それぞれどちらでも登録した用語のアノテーションが可能ですが、登録プロセスや上記の要件の実現にも使い勝手が異なっています。
また、登録したファセットと紐付けることで、同じ用語でも既存の標準辞書によるものとは区別してカスタム辞書としてのアノテーションを取得することが可能です。

#ユーザー辞書での登録

Webベースの管理コンソールから「コンテンツ分析コレクション」を作成し、そこでユーザー辞書やパターンを登録することができます。
![1_WEX辞書_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103796/741d75c8-f952-d240-e7e0-8045683b261a.png)


ユーザー辞書は個々の語句を登録する他にはGUIからCSVファイルで一括インポートすることができます。また、ユーザー辞書登録時に作成される <任意の辞書名>.fdic.xmlファイルをサーバーのディレクトリー（/home/esadmin/esdata/master_config/<コレクションID>.indexservice/resource/adic）に直接配置することでも登録可能です。

管理コンソールのGUIからの登録画面は項目が充実しています。XMLファイル上の個々の項目の対応はこんな感じになります。
![3_WEX辞書_GUI_op_ppt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103796/deb95966-d5cf-5dfe-46f3-d176c1a1360e.png)

* 大文字・小文字については「大文字/小文字を無視」（Ignore Case)のチェック項目があり，差異を吸収することができるのは便利。
* 同義語は「等価語」（Equivalent Term）として登録することができ、三人称変化や名詞でも -s の他に -esと変化する場合や 動詞の不規則変化などは「追加のワード形式」という枠が用意されています。しかしこれは、**不規則な変化も含めて手動で明示的に登録する必要がある**ことを意味します。
* 複合語もスペースやハイフンを挟んだ個々の語句として登録することになります。

#パターンでの登録

管理コンソールからの登録UIは、コンテンツ分析コレクションの「アノテーター」-「パターン・マッチャー・アノテーター」からアクセスします。
![5_WEX辞書_patt1_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103796/b3418d8d-d6a5-9094-e8bb-00493794cf4c.png)
![6_WEX辞書_patt2_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103796/115d4f6e-47d2-5cda-aaee-ebacf5a38473.png)
入力画面はユーザー辞書と異なりプレーンなエディターで、個々の語句パターンの登録はXMLの書式において正規表現で記述する必要があり、入力には一定の知識が必要となります。
![7_WEX辞書_patt3_n2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103796/ab3c56b2-d585-dd9b-edc2-5ea3035f2a4f.png)


XMLの書式は [公式ドキュメント](https://www.ibm.com/support/knowledgecenter/ja/SS8NLW_11.0.1/com.ibm.discovery.es.ta.doc/iiysatextanalrules.htm "コンテンツ分析コレクションのカスタム・ルール・ファイル - IBM Knowledge Center") にフォーマットの説明があります。

* パターンでは、**レックス（lex）制約タイプで lemma**（レンマ、形態素解析の語句変化における基本形）**を指定すれば、複数形などの語句変化は吸収して柔軟にアノテーションされる**という大きな利点があります。
 (例：基本形：activity -> 複数形：activities)
* 大文字・小文字については、デフォルト状態では語句の先頭文字が大文字、またはすべてが大文字の場合だけ差異を吸収します。すなわち、"wifi"などの用語は実際の文章中に"WiFi"といった文字列で出現することもありますが、"wifi"としてパターンに登録されているとマッチングされません。
* パターンではユーザー辞書のときのような、CSVファイルからの一括登録の方法はありませんが、ユーザー辞書と同様に <任意の辞書名>.patファイルをサーバーのディレクトリー（/home/esadmin/esdata/master_config/<コレクションID>.indexservice/resource/pattern）に直接配置することでも登録可能です。

#比較まとめ

運用としては、ExcelまたはCSVファイル上のリストから、Excelマクロやnode.jsなどのプログラムで自動でXMLを作成することが考えられます。サーバー上のXMLファイルを置き換えた後には、管理コンソールの分析コレクションの管理画面から、分析リソースのデプロイや再インデックス処理が必要です。

以下ユーザー辞書とパターンでの「揺らぎ」への対応や登録運用への対応をまとめました。

| 揺らぎ要件 | 例   | ユーザー辞書 | パターン |
|:-----------|:------------|:-------------|:------------|
| 複数形、三人称、be動詞　    | "activity" -> "activities"  "as is"  | <font color="Red">△</font> 変化形を個別に登録する必要がある  | <font color="Blue">◯</font> lemma（基本形）をlex制約で登録すれば変化形にも対応可能
| 比較級・最上級   | "low" -> "lowest" "one or more" | <font color="Red">△</font>（同上） |<font color="Blue">◯</font>（同上）|
| 過去分詞、現在分詞 |"certify" -> "certified" | <font color="Red">△</font>（同上） |<font color="Blue">◯</font>（同上
| 派生品詞         | "periodic" -> "periodical"          | <font color="Red">△</font>（同上） |<font color="Blue">◯</font>（同上
| 大文字・小文字  | "Frequency"  "Hz" "WiFi" | <font color="Blue">◯</font>  Ignoreチェックで対応可能       | <font color="Red">△</font> 先頭の１文字のみ、またはすべて大文字のときのみ対応（解決策あり、後述）

| 運用要件 | ユーザー辞書 | パターン |
|:-----------|:-------------|:------------|
| GUIから登録  | <font color="Blue">◯</font> 分かりやすい編集画面あり | <font color="Red">△</font> プレーンテキストエディターに正規表現のXMLを記述 
| 一括登録  | <font color="Blue">◯</font> CSVファイルのインポート　　　　　　XMLファイルの配置 | XMLファイルの配置
#辞書とパターンを併用した場合の課題点

先述のように、辞書とパターンは要件を満たすのに一長一短の特徴があります。「それでは、語形変化のある語句はパターンで、それ以外は辞書で、といった併用すればいいじゃないか」ということを思いつきますが、その際は二語以上の語句からなる複合語で課題が出てきます。
例えば、"LEICA lenses"といった複合語がパターンに登録されていても、辞書側に"LEICA" といった語句があると、入力文に "LEICA lenses"という文字列が登場してもアノテーションされません。これは、**WEXの優先順として、辞書にある"LEICA”や"lens"が先に認識され、パターンのマッチングはその解析の後の処理になっているので、ひとかたまりの文字列 "LEICA lenses"としてのマッチング対象にならない**ためです。
テストしてみたところ、ユーザー辞書の "LEICA"の登録を削除してパターン側だけで行ったところ、入力文 "LEICA lenses"は、lenses が lemma としての lens のレックス制約で登録されていたので複数形でもチェックされ、アノテーションされるようになりました。


#解決策の一例：パターンのみによるアノテーション

カスタム辞書構築において、アノテーション対象として登録する用語の範囲が少ない場合は、ユーザー辞書をGUIから登録する方が向いています。登録対象が名詞の専門用語など不可算の名詞とその同義語の範囲に収まっている場合も、CSVファイルでインポートできるユーザー辞書の方が使い勝手が良いと言えます。
しかし、対象の用語が大量で運用開始後も定期的に辞書をメンテナンスしていく必要があるようなケースで、変化形も含めて厳密にアノテーションする為には、すべての語句の「揺らぎ」を登録する必要があり、運用上実用的ではありません。また、すでに見たように、辞書とパターン併用での運用にも課題点があります。

これらの要件上で提案できる辞書構築は以下の運用方針です。
1. 該当の用語に関してはユーザー辞書を用いないこと
2. 用語はパターンを用いてlemmaで登録すること

大文字小文字の認識の課題で、パターンで通常は先頭のみまたは単語全部が大文字の場合にしか揺らぎに対応しない件については，WEXのパターンマッチャーの内部でJava の正規表現ライブラリを使っていることを利用し、

```xml
(?i)<キーワード>
```
とマッチングルールを書くことで，大文字小文字区別されなくする方法をとることができます。

#アノテーション結果の確認方法：RESTコール

最後に、ユーザー辞書やパターンでファセットに紐づけて登録した用語が実際にアノテーションされているかを確認方法を紹介します。GUIの分析画面から確認してもよいですが、ここではAPIを用いてRESTのコール結果を用います。
POSTMANなどのREST Clientツールも使えますが、ここではCurlコマンドで書いています。

```curl:Curlコマンドの例
curl -X POST  -H "Content-Type: multipart/form-data" -F "collection=[対象のcollectionID]" -F "output=xmi" -F "language=en" -F "text=[解析対象のテキスト]" "http://[WEXのホスト名]:8393/api/v10/analysis/text"
```
参考：[REST APIs](https://www.ibm.com/support/knowledgecenter/en/SS8NLW_11.0.2/com.ibm.discovery.es.ap.doc/iiysprestapi.html "REST APIs - IBM Knowledge Center") 

以下の文章を対象にしてみます。
**"The first mirrorless camera commercially marked was the Epson R-D1 (released in 2004). followed by the Leica M8. The Micro Four Thirds system, whose first camera was the Panasonic Lumix DMC-G1,was released in Japan in October 2008."**
（引用元は [こちら](https://en.wikipedia.org/wiki/Mirrorless_interchangeable-lens_camera "Mirrorless interchangeable-lens camera - Wikipedia") ）

```txt:入力例
curl -X POST  -H "Content-Type: multipart/form-data" -F "collection=xxxx" -F "output=xmi" -F "language=en" -F "text=The first mirrorless camera commercially marketed was the Epson R-D1 (released in 2004), followed by the Leica M8. The Micro Four Thirds system, whose first camera was the Panasonic Lumix DMC-G1, was released in Japan in October 2008." "http://xxx.xxx.xxx:8393/api/v10/analysis/text" > D:\result.xml
```

"Micro Four Thirds system"といった複合語の文字列を専門用語としてパターンで登録したい場合、それぞれの語句の lemma（基本形）が必要ですが、応答されたXMLの中に以下のような表現でkeyの値として含まれるので確認することができます。（Thirds の lemmaは third であることが分かります）

```xml:出力例
：（略）
<tt2:Lemma xmi:id="1263" key="micro" partOfSpeech="3" frost_ExtendedPOS="0"/>
<tt2:Lemma xmi:id="1274" key="four" partOfSpeech="10" frost_ExtendedPOS="0"/>
<tt2:Lemma xmi:id="1284" key="third" partOfSpeech="3" frost_ExtendedPOS="0"/>
：（略）
<tt2:Lemma xmi:id="1294" key="system" partOfSpeech="3" frost_ExtendedPOS="0"/>
：（略）
```

そこで以下のようなパターン用のXMLファイルを作成し、GUIでのコピペあるいはファイル配置によって登録します。ここでは一度に "NEX" "Micro Four Thirds System" "mirrorless camera" の３つの語句を作成済みのファセットツリー"mirrorless_camera"に紐づけて登録しています。miタグで囲われた部分が一つ一つのルールになります。

```xml:cameras.pat（パターン）
<?xml version="1.0" encoding="UTF-8"?>
<pattern-list lang="en">
    <mi category="$.mirrorless_camera" value="NEX">
        <w id="0" str="/((?i)NEX)/"/>
    </mi>
    <mi category="$.mirrorless_camera" value="Micro Four Thirds System">
        <w id="0" lex="micro"/>
        <w id="1" lex="four"/>
        <w id="2" lex="third"/>
        <w id="3" lex="system"/>
    </mi>
    <mi category="$.mirrorless_camera" value="mirrorless camera">
        <w id="0" lex="mirrorless"/>
        <w id="1" lex="camera"/>
    </mi>
</pattern-list>
```

反映後、もう一度先のRESTコールを行うと、応答結果のXMLファイルで以下の項目があり、ファセットのカテゴリー"mirrorless_camera"に登録した辞書やパターンとしてヒットしたことが確認できました。

```xml:result.xml（一部）
：（略）
<annotation_type:ContiguousContext xmi:id="1751" sofa="15" begin="117" end="141" category="$.mirrorless_camera" representation="Micro Four Thirds System"/>
：（略）
```

以下のような文字列は（まだ）辞書にない言葉と解釈されたということになります。

```xml:result.xml（一部）
：（略）
<annotation_type:ContiguousContext xmi:id="1823" sofa="15" begin="170" end="189" category="$._phrase.noun_phrase.nouns" representation="Panasonic Lumix DMC"/>
：（略）
```

#まとめ

WEXのカスタム辞書の構築において、パターンを用いて語句の基本形であるlemmaをレックス制約で登録すると、標準辞書にある語句の場合は、複数形変化や動詞変化に対応でき、全大文字、先頭大文字にも対応することが確認できました。
用語が少量であったり、日本語の名詞など変化が少ない語句であれば、同義語の登録だけでよく「ユーザー辞書」への一括登録の方が使い勝手が良いですが、変化のある言語で揺らぎを正確にコントロールしたい場合は登録運用のコストが跳ね上がるので、パターンのみに基本形で登録すると、複合語における辞書の影響も回避でき、アノテーションされる精度が高まるのでがお勧めです。