ユーザ発話の曖昧な表現をマッチングさせる方法をご紹介します。
実装方法1 – グラフ構造変換
<pattern>
内に記述した文字列は、コンパイル時に形態素単位に分割され、グラフ構造に変換されます。このグラフ構造変換やマッチング動作について理解を深めることで、的確なパターンを記述することができます。
xAIML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<category> <pattern>_嫌い</pattern> <template> そんなこと言わないで </template> </category> <category> <pattern>ラーメン食べたい</pattern> <template> おいしいよね </template> </category> <category> <pattern>ラーメン作りたい</pattern> <template> 料理するんですね </template> </category> <category> <pattern>ラーメン*</pattern> <template> そうなんですね </template> </category> <category> <pattern>今日の天気は</pattern> <template> 晴れるといいね </template> </category> |
グラフ構造変換結果
上記のxAIMLがグラフ構造に変換されると下記のようになります。
マッチング動作
- ユーザ入力も同様に形態素分割され、前方からグラフ構造にマッチング試行されます。
_
と*
は1形態素以上の文字列とマッチングします。- マッチ優先度は、
_
>形態素>*
となります。 - 全角と半角は区別しません。
<pattern>
内に全角で記述していたとしても、半角のユーザ入力にマッチします。また逆の場合でも同様です。
実行結果
1 2 3 4 5 6 7 8 |
user > ラーメン嫌い bot > そんなこと言わないで user > ラーメンを買いたい bot > そうなんですね user > 今日の予定は bot > NOMATCH |
実装方法2 – <pattern>タグを複数記述
1つの<category>
の中に、複数の<pattern>
を記述することで、複数のパターンにマッチさせることができます。
xAIML
1 2 3 4 5 6 7 |
<category> <pattern>ラーメン食べたい</pattern> <pattern>ラーメンを食べる予定</pattern> <template> おいしいよね </template> </category> |
実行結果
1 2 3 4 |
user > ラーメン食べたい bot > おいしいよね user > ラーメンを食べる予定 bot > おいしいよね |
実装方法3 – マッチングレベル制御
<pattern>
のlevel
属性によって、マッチングのレベルを制御することができます。
ユーザ発話と<pattern>
は、言語処理されて類義語展開、抽象化された文字列としてマッチングが行われます。
マッチングレベルとマッチング動作については以下の例をご確認ください。
ユーザ発話
① ラーメン食べたい
② らーめん食べたい
③ ラーメンを食べたい
④ ラーメンを頂きたい
⑤ うどんを頂きたい
② らーめん食べたい
③ ラーメンを食べたい
④ ラーメンを頂きたい
⑤ うどんを頂きたい
patternタグ
1 |
<pattern level="下表のLevelを参照">ラーメン食べたい</pattern> |
マッチング結果
Level |
展開結果 | マッチング動作 | マッチする発話 |
exact |
ラーメン 食べる たい |
表層のみ展開し、読みマッチは行わない。 | ① |
surface |
ラーメン名詞:ラーメン 食べる動詞語幹:タベ たいタイ |
表層か読み&品詞のどちらかが一致すればマッチ成立。 | ① ② |
normalization |
ラーメン名詞:ラーメン<noun> 食べる動詞語幹:タベ |
表層か読み&品詞のどちらかが一致すればマッチ成立。(助詞・副詞を除外) | ① ② ③ |
synonym |
ラーメン名詞:ラーメン<noun> 食べる動詞語幹:タベ 頂く食事召し上がる戴く召しあがる喰らう召上る喰う食う召上がる召す上がる食する食む食らう召し上る |
表層か読み&品詞か類義語のどれかが一致すればマッチ成立。 | ① ② ③ ④ |
hypernym |
ラーメン名詞:ラーメン<noun> <Dish><Food> 食べる動詞語幹:タベ 頂く食事召し上がる戴く召しあがる喰らう召上る喰う食う召上がる召す上がる食する食む食らう召し上る |
表層か読み&品詞か類義語か上位概念のどれかが一致すればマッチ成立。 | ① ② ③ ④ ⑤ |
正規表現(level=regex
)の場合
1 |
<pattern level="regex">(ラーメン)?食べたい?</pattern>
⇒ patternに記述した正規表現に一致した場合、マッチ成立 |
- 正規表現マッチの場合は、他の
level
のパターンマッチより優先します。 - 入力との正規表現マッチは
<topic>
/<that>
/<pattern>
のlabel
属性に一致した後に行います。 - 他に正規表現マッチする候補が存在しても、先に
<topic>
/<that>
/<pattern>
のlabel
属性に一致するパターンが存在した場合、次の正規表現マッチ候補の探索を行わず、regex
以外のパターンマッチを行います。 - 正規表現摘出した文字列はワイルドカードマッチと同様に
<star>
を利用可能です。
ご注意
正規化以降のマッチングレベル(normalization, synonym, hypernym)はアンカーカテゴリ(topic/mode/pattern/label/that/id/emotion)がすべて「*」だったときのみ動作いたします。
実装方法4 – ワイルドカード
<pattern>
でワイルドカード(_
, *
)を指定すると、一形態素以上の任意の文字列にマッチします。マッチした文字列は
<star>
で抽出できます。
xAIML
1 2 3 4 5 6 |
<category> <pattern>*ラーメン食べたい</pattern> <template> おいしいよね </template> </category> |
実行結果
1 2 3 4 5 6 7 8 |
user > 今日はラーメン食べたい bot > おいしいよね user > お店でラーメン食べたい bot > おいしいよね user > ラーメン食べたい bot > NOMATCH |
実装方法5 – partial属性を指定
<pattern>
のpartial
属性にtrue
を指定すると、グラフ構造変換の際にパターンを拡幅します。すでにワイルドカード(
*
, _
)がある側は拡幅されません。パターンマッチングの優先度は*
よりもpartial="true"
の方が高くなります。また、拡幅したパターンにマッチした文字列(下記例の<?>部分)は<star>
で抽出できません。
xAIML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<category> <pattern partial="true">ラーメン食べたい</pattern> <template> おいしいよね </template> </category> <!-- 上記patternは、下記のように拡幅されます。 ただし、star要素による文字列抽出は不可です。 <pattern>ラーメン食べたい</pattern> <pattern><?> ラーメン食べたい</pattern> <pattern>ラーメン食べたい <?></pattern> <pattern><?> ラーメン食べたい <?></pattern> --> |
実行結果
1 2 3 4 5 6 7 8 9 10 11 |
user > ラーメン食べたい bot > おいしいよね user > 今日はラーメン食べたい bot > おいしいよね user > ラーメン食べたいね bot > おいしいよね user > 今日はラーメン食べたいね bot > おいしいよね |
実装方法6 – level属性とpartial属性を指定
<pattern>
のlevel
属性とpartial
属性は同時に指定できます。
xAIML
1 2 3 4 5 6 |
<category> <pattern level="surface" partial="true">ラーメン食べたい</pattern> <template> おいしいよね </template> </category> |
実行結果
1 2 3 4 5 6 7 8 9 10 11 |
user > ラーメン食べたい bot > おいしいよね user > 今日はラーメン食べたい bot > おいしいよね user > ラーメン食べたいね bot > おいしいよね user > 今日はラーメン食べたいね bot > おいしいよね |