スマート・マッチング : ディクショナリの使用
インターシステムズは、InterSystems IRIS® 自然言語処理 (NLP) を非推奨Opens in a new tabにしました。インターシステムズ製品の今後のバージョンから削除される可能性があります。以下のドキュメントは、既存ユーザのみに向けたリファレンスとしています。代替のソリューションを見いだすためのサポートを必要とする既存ユーザはインターシステムズのサポート窓口Opens in a new tabにお問い合わせください。
スマート・マッチングとは、NLP インデックス作成プロセスの結果を、ディクショナリ、分類法、またはオントロジといった形で所有している外部の知識と組み合わせることです。こうしたインデックス作成結果により、どの単語をまとめて概念や関係を形成するかが特定されるため、一致の品質を判断することが可能になり、NLP マッチングが “スマート” になります。例えば、NLP は、ディクショナリ用語である "flu" に一致する語が、実際にインデックス付きテキスト・ソースで "flu"、"bird flu"、または “no flu symptoms” という概念を示しているのかを識別できます。2 番目のケースは部分一致と呼ばれますが、この場合の一致は、インデックス付けされたテキスト・ソースのエンティティにディクショナリ用語が正確に対応する完全一致の場合とは異なる扱いが必要なこと (または異なる扱いが可能なこと) は明らかです。3 番目のケースの一致では、否定付きの部分一致と認識されます。
スマート・マッチングを実行するには、ディクショナリを作成または取得する必要があります。ディクショナリの作成と入力については、前の章で説明されています。ディクショナリを生成したら、そのコンテンツを使用してマッチング処理を実行できます。
ディクショナリ・マッチングの仕組み
NLP は、ソース・テキスト内の同じレベルの構造に対して、ディクショナリの各用語をマッチングさせます (コンセプト用語はソース・テキストのコンセプトに対して、CRC 用語はソース・テキストの CRC に対してマッチングさせます)。こうして一致する語は、完全一致または部分一致になります。用語とソース・テキストが完全一致の場合、NLP ではその用語に関連付けられたディクショナリ項目でそのソース・テキストの一節にタグを付けます。用語とソース・テキストが完全一致ではない場合、NLP はそれらの一致の程度をスコアリングします。この一致スコアには、各コンポーネントのエンティティ (概念または関係) に対する一致スコアの計算が含まれ、必要な場合は、このエンティティの一致スコアを使用して、CRC、パスまたは文の一致スコアを計算します。構成された最小一致スコアに部分一致のスコアが達すると、NLP ではその用語に関連付けられたディクショナリ項目でそのソース・テキストの一節にタグを付けます (%iKnow.Matching.MatchingProfileOpens in a new tab の MinimalMatchScoreOpens in a new tab プロパティを参照してください)。
一致スコア
NLP では、一致スコア、浮動小数点数 (ディクショナリ用語間で検出されたエンティティの一致のすべてを計算)、およびソース・テキストのユニットが生成されます。エンティティの一致では、その一致スコアが 0 (一致なし) および 1 (完全一致) の間の範囲になります。CRC 一致またはパス一致では、その一致にこの範囲を含みますが、1 より大きくなることもあります。このスコアの計算に使用されるアルゴリズムは複雑ですが、以下の考慮事項があります。
-
エンティティの完全一致は、完全 (同じ順番の同じ単語) または散在 (異なる順番の同じ単語) があります。散在一致の一致スコアは、マッチング・プロファイルの ScatteredMatchMultiplierOpens in a new tab プロパティの値に 1 (完全一致) を乗算することで確定されます。
-
エンティティ (概念または関係) の部分一致では、ディクショナリ用語と一致するソース・テキストの文字列の割合に基づいてパーセンテージが割り当てられます。
-
エンティティの部分一致で、一致する関係に割り当てられる値は、一致する概念の半分のみです。マッチング・プロファイルの RelationshipScoreMultiplierOpens in a new tab プロパティを設定して、この割合を変更できます (例えば、関係一致と概念一致を等しく評価します)。
-
CRC、パスまたは文のマッチング時には、エンティティの一致から一致スコアが追加されてから、ディクショナリ用語の長さによる除算、マッチング・エンティティの数による乗算、そして DisorderMultiplierOpens in a new tab プロパティ、すなわちソース・テキストのユニットとディクショナリ用語の間での不一致の程度を表す値による乗算が実行されます。
-
エンティティが否定の一部である場合、エンティティの一致スコアは変更できます。既定では、NegationMultiplierOpens in a new tab のプロパティ値は 1 となり、一致スコアの計算では肯定エンティティと否定されたエンティティを等価として扱うようになります。通常、この既定をお勧めします。NegationMultiplier を 0 に設定することもでき、これにより一致スコアの計算では否定されたエンティティをスキップします。ほとんどの場合、0 の値によってこれらの一致が全体的にスキップされることになりますが、十分な否定されない一致エンティティとの複合一致により、MinimalMatchScore しきい値を超えるスコアを取得する場合は例外です。また、このプロパティを 0 ~ 1 の値に設定することもできます。これにより、否定されたエンティティのエンティティ・レベルの一致スコアが変更されるので、それらのスコアは部分一致と見なされます。例えば、値が 0.5 では、否定されたエンティティに対してエンティティ・レベルのスコアを得ることになります。
前述の式は、一致スコアを取得するための完全な数式ではありません。これは、NLP による一致スコアの計算時に使用される主な考慮事項を示すために用いられています。
NLP に用意されているマッチング・プロファイル (%iKnow.Matching.MatchingProfileOpens in a new tab) は、前述の数値プロパティなどで構成されています。NLP では、一致スコアの計算時にこのマッチング・プロファイルが使用されます。NLP では、マッチング・プロファイル用に既定のプロパティ値が用意されています。特に指定がない場合は、この既定のマッチング・プロファイルが各ディクショナリに割り当てられます。この既定のマッチング・プロファイルによって、多くのアプリケーションに対応する正確なマッチングが提供されます。カスタム・マッチング・プロファイルの作成と割り当てについてはこの章の残り部分で説明されます。
文字列のマッチング
%iKnow.Matching.MatchingAPIOpens in a new tab クラスを使用して、テキスト文字列と生成された 1 つまたは複数のディクショナリとの間でマッチングを実行できます。文字列のマッチングには、以下の 2 種類があります。
-
エンティティ長文字列のマッチング
-
複数エンティティを含む文字列のマッチング。この文字列は 1 つ以上の文を含む場合があります。
エンティティ文字列のマッチング
GetDictionaryMatches()Opens in a new tab メソッドは、単一エンティティ文字列をディクショナリとマッチングさせて、一致した項目を返します。このメソッドは文字列を単一エンティティとして扱うので、きわめて固有の一致情報を得ることができます。GetDictionaryMatches() は文字列変数を取得するので、単一エンティティ文字列をインデックス化して、ディクショナリとマッチングさせる必要はありません。
SET domn="entitytestdomain"
IF (##class(%iKnow.Domain).NameIndexExists(domn))
{ SET domo=##class(%iKnow.Domain).NameIndexOpen(domn)
SET domId=domo.Id
}
ELSE {
SET domo=##class(%iKnow.Domain).%New(domn)
DO domo.%Save()
SET domId=domo.Id }
/* ... */
CreateDictionary
SET dictname="AviationTerms"
SET dictdesc="A dictionary of aviation terms"
SET dictId=##class(%iKnow.Matching.DictionaryAPI).CreateDictionary(domId,dictname,dictdesc)
IF dictId=-1 {WRITE "Dictionary ",dictname," already exists",!
GOTO ResetForNextTime }
ELSE {WRITE "created a dictionary ",dictId,!}
PopulateDictionary
SET itemId=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryItem(domId,dictId,
"aircraft",domId_dictId_"aircraft")
SET term1Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(domId,itemId,
"airplane")
SET term2Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(domId,itemId,
"single-engine airplane")
SET term3Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(domId,itemId,
"helicopter")
DisplayDictionary
SET stat=##class(%iKnow.Matching.DictionaryAPI).GetDictionaryItemsAndTerms(.result,domId,dictId)
SET i=1
WHILE $DATA(result(i)) {
WRITE $LISTTOSTRING(result(i),",",1),!
SET i=i+1 }
WRITE "End of items in dictionary ",dictId,!!
DoMatching
SET mystring="A small single-engine two-person airplane cabin"
SET stat=##class(%iKnow.Matching.MatchingAPI).GetDictionaryMatches(.num,domId,mystring,$LB(dictId))
IF stat'=1 {WRITE "get matches status is:",$System.Status.DisplayError(stat),!
QUIT }
WRITE "The string is: ",mystring,!
WRITE "The matches are:",!
SET j=1
WHILE $DATA(num(j)) {
WRITE "match number ",j," is ",$LISTTOSTRING(num(j)),!
SET j=j+1 }
WRITE "End of match items for dictionary ",dictId,!!
ResetForNextTime
IF dictId = -1 {
SET dictId=##class(%iKnow.Matching.DictionaryAPI).GetDictionaryId(domId,dictname)}
SET stat=##class(%iKnow.Matching.DictionaryAPI).DropDictionary(domId,dictId)
IF stat {WRITE "deleted dictionary ",dictId,! }
GetDictionaryMatches() は一致単語のビット・マップを提供することで、文字列内の各単語とディクショナリ用語との一致を表示します。例えば、00101 はディクショナリ用語 “single-engine airplane” と文字列 “A small single-engine two-person airplane / cabin” との一致を示します。このビット・マップは、マッチングが完了すると停止するため、単語 “cabin” のビットはありません。この例において、単語 “single-engine” と “airplane” はディクショナリ用語と文字列で同じ順序であるため、散在ブーリアンは 0 です。
各ディクショナリのマッチングでは、一致要素のリストが返されます。前の例におけるマッチングでは、以下のように一致要素のリストが返されます (ID 番号は各自で異なる場合があります)。
位置 | 意味 | 例における値 |
---|---|---|
1 | ディクショナリ ID | 6 |
2 | 項目 ID | 5 |
3 | ディクショナリ項目 URI (ドメイン ID + ディクショナリ ID + 項目の値) | 26aircraft |
4 | 用語 ID | 13 |
5 | 用語の値 | single-engine airplane |
6 | 要素 ID (用語 ID と同じ) | 13 |
7 | 一致タイプ (term、format、または unknown) | 用語 |
8 | 一致スコア | .333333 |
9 | 一致単語のビット | 00101 |
10 | 散在ブーリアン | 0 |
11 | 形式出力 | null |
文文字列のマッチング
GetMatchesBySource()Opens in a new tab メソッドは、複数エンティティ文字列をディクショナリとマッチングさせて、一致した項目を返します。(通常、このような文字列は文の長さ (またはそれ以上) となります。)最初に文字列をインデックス化してから、ディクショナリとマッチングさせる必要があります。以下の例は、AviationTerms ディクショナリに対して文字列をマッチングさせます。
DomainCreateOrOpen
SET dname="onestringdomain"
IF (##class(%iKnow.Domain).NameIndexExists(dname))
{ SET domoref=##class(%iKnow.Domain).NameIndexOpen(dname)
GOTO DeleteOldData }
ELSE
{ SET domoref=##class(%iKnow.Domain).%New(dname)
DO domoref.%Save()
GOTO LoadString }
DeleteOldData
SET stat=domoref.DropData()
IF stat { GOTO LoadString }
ELSE { WRITE "DropData error ",$System.Status.DisplayError(stat)
QUIT}
LoadString
SET domId=domoref.Id
SET myloader=##class(%iKnow.Source.Loader).%New(domId)
SET ^mystring="A single-engine airplane reported poor visibility and strong gusty winds. "_
"No winds were predicted by local airport ground personnel."
DO myloader.BufferSource("ref",^mystring)
DO myloader.ProcessBuffer()
GetExtId
DO ##class(%iKnow.Queries.SourceAPI).GetByDomain(.result,domId,1,20)
SET i=1
WHILE $DATA(result(i)) {
SET extId = $LISTGET(result(i),2)
SET i=i+1 }
CreateDictionary
SET dictname="AviationTerms"
SET dictdesc="A dictionary of aviation terms"
SET dictId=##class(%iKnow.Matching.DictionaryAPI).CreateDictionary(domId,dictname,dictdesc)
IF dictId=-1 {WRITE "Dictionary ",dictname," already exists",!
GOTO ResetForNextTime }
ELSE {WRITE "created a dictionary ",dictId,!}
PopulateDictionaryItem1
SET itemId=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryItem(domId,dictId,
"aircraft",domId_dictId_"aircraft")
SET term1Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(domId,itemId,
"single-engine airplane")
SET term2Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(domId,itemId,
"helicopter")
PopulateDictionaryItem2
SET itemId2=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryItemAndTerm(domId,dictId,
"weather",domId_dictId_"weather")
SET i2term1Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(domId,itemId2,
"strong winds")
SET i2term2Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(domId,itemId2,
"visibility")
SET i2term3Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(domId,itemId2,
"winds")
DisplayDictionary
SET stat=##class(%iKnow.Matching.DictionaryAPI).GetDictionaryItemsAndTerms(.result,domId,dictId)
SET i=1
WHILE $DATA(result(i)) {
WRITE $LISTTOSTRING(result(i),",",1),!
SET i=i+1 }
WRITE "End of items in dictionary ",dictId,!!
DoMatching
SET stat=##class(%iKnow.Matching.MatchingAPI).GetMatchesBySource(.num,domId,extId,$LB(dictId))
IF stat'=1 {WRITE "get matches status is:",$System.Status.DisplayError(stat),!
QUIT }
WRITE "The string is: ",^mystring,!
WRITE "The matches are:",!
SET j=1
WHILE $DATA(num(j)) {
WRITE "match ",j,": ditem ",$LISTGET(num(j),4),
" dterm ",$LISTGET(num(j),5),
" matchscore ",$LISTGET(num(j),8),
" negated? ",$LISTGET(num(j),15),!
SET j=j+1 }
WRITE "End of match items for dictionary ",dictId,!!
ResetForNextTime
IF dictId = -1 {
SET dictId=##class(%iKnow.Matching.DictionaryAPI).GetDictionaryId(domId,dictname)}
SET stat=##class(%iKnow.Matching.DictionaryAPI).DropDictionary(domId,dictId)
IF stat {WRITE "deleted dictionary ",dictId,! }
ELSE { WRITE "DropDictionary error ",$System.Status.DisplayError(stat) }
以下は、文字列の “No winds” と項目 “weather” のディクショナリ用語 “winds” とのマッチングとなります。(この一致文字列は %List 形式で返され、5,6,12,26weather,33,0,6,.5,1,0,1,1,1,1,1 のようにコンマ区切りの文字列で表示されます。)これらの要素の値について、以下に説明します。
位置 | 意味 | 例における値 |
---|---|---|
1 | 一致数 | 5 |
2 | ディクショナリ ID | 6 |
3 | 項目 ID | 12 |
4 | ディクショナリ項目 URI (ドメイン ID + ディクショナリ ID + 項目の値) | 26weather |
5 | 用語 ID | 33 |
6 | ターゲット・タイプ | 0 |
7 | ターゲット ID | 6 |
8 | 一致スコア | .5 |
9 | 一致概念カウント | 1 |
10 | 一致関係カウント | 0 |
11 | 部分一致カウント | 1 |
12 | パスの最初の一致位置 | 1 |
13 | パスの最後の一致位置 | 1 |
14 | が整列 | 1 |
15 | 否定されたエンティティのカウント | 1 |
ソースのマッチング
このドキュメント内の例で使用されているコーディングおよびデータの詳細は、"サンプル・プログラムに関するメモ" を参照してください。
GetTotalItemScoresBySource()Opens in a new tab メソッドは、ソースをディクショナリとマッチングさせて、それぞれのディクショナリ項目について一致スコアを返します。以下の 2 つの例では、ドメイン固有のディクショナリを使用します。ディクショナリの定義、およびディクショナリを参照するあらゆる %iKnow.Matching.DictionaryAPIOpens in a new tab メソッドにおいて、ドメイン ID を 0 に指定します。ドメイン内でディクショナリを使用するあらゆる %iKnow.Matching.MatchingAPIOpens in a new tab メソッドにおいて、ディクショナリ ID を負の数に指定します。したがって、SET dictId=-^mydictId となります。
以下の例では、ドメイン内の全ソースを AviationTermsND ディクショナリとマッチングさせて、それぞれのディクショナリ項目について各ソースの一致スコアを返します。このプログラムを実行する前に、ディクショナリを作成する必要があります。
CreateDictionary
SET ^mydictname="AviationTermsND"_$HOROLOG
SET dictdesc="A dictionary of aviation terms"
SET ^mydictId=##class(%iKnow.Matching.DictionaryAPI).CreateDictionary(0,^mydictname,dictdesc)
IF ^mydictId=-1 {WRITE "Dictionary ",^mydictname," already exists",!
QUIT }
ELSE {WRITE "created a dictionary ",^mydictId,!}
PopulateDictionaryItem1
SET itemId=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryItem(0,^mydictId,
"aircraft",0_^mydictId_"aircraft")
SET term1Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(0,itemId,
"single-engine airplane")
SET term2Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(0,itemId,
"helicopter")
PopulateDictionaryItem2
SET itemId2=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryItemAndTerm(0,^mydictId,
"weather",0_^mydictId_"weather")
SET i2term1Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(0,itemId2,
"strong winds")
SET i2term2Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(0,itemId2,
"visibility")
SET i2term3Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(0,itemId2,
"winds")
PopulateDictionaryItem3
SET itemId=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryItem(0,^mydictId,
"flight plan",0_^mydictId_"flight plan")
SET term3Id=##class(%iKnow.Matching.DictionaryAPI).CreateDictionaryTerm(0,itemId,
"flight plan")
DisplayDictionary1
SET stat=##class(%iKnow.Matching.DictionaryAPI).GetDictionaryItemsAndTerms(.result,0,^mydictId)
WRITE "Status is: ",stat,!
SET i=1
WHILE $DATA(result(i)) {
WRITE $LISTTOSTRING(result(i),",",1),!
SET i=i+1 }
WRITE "End of items in dictionary ",^mydictId,!!
DomainCreateOrOpen
SET dname="mydomain"
IF (##class(%iKnow.Domain).NameIndexExists(dname))
{ WRITE "The ",dname," domain already exists",!
SET domoref=##class(%iKnow.Domain).NameIndexOpen(dname)
GOTO DeleteOldData }
ELSE
{ WRITE "The ",dname," domain does not exist",!
SET domoref=##class(%iKnow.Domain).%New(dname)
DO domoref.%Save()
WRITE "Created the ",dname," domain with domain ID ",domoref.Id,!
GOTO ListerAndLoader }
DeleteOldData
SET stat=domoref.DropData()
IF stat { WRITE "Deleted the data from the ",dname," domain",!!
GOTO ListerAndLoader }
ELSE { WRITE "DropData error ",$System.Status.DisplayError(stat)
QUIT}
ListerAndLoader
SET domId=domoref.Id
SET flister=##class(%iKnow.Source.SQL.Lister).%New(domId)
SET myloader=##class(%iKnow.Source.Loader).%New(domId)
QueryBuild
SET myquery="SELECT Top 10 ID AS UniqueVal,Type,NarrativeFull FROM Aviation.Event"
SET idfld="UniqueVal"
SET grpfld="Type"
SET dataflds=$LB("NarrativeFull")
UseLister
SET stat=flister.AddListToBatch(myquery,idfld,grpfld,dataflds)
IF stat '= 1 {WRITE "The lister failed: ",$System.Status.DisplayError(stat) QUIT }
UseLoader
SET stat=myloader.ProcessBatch()
IF stat '= 1 {WRITE "The loader failed: ",$System.Status.DisplayError(stat) QUIT }
DoMatching
SET dictId=-^mydictId
SET num=0
FOR j=1:1:10 {SET extId=##class(%iKnow.Queries.SourceAPI).GetExternalId(domId,j)
SET mstat=##class(%iKnow.Matching.MatchingAPI).GetTotalItemScoresBySource(.mresult,domId,
extId,$LB(dictId))
IF mstat '=1 {WRITE "End of sources",! QUIT }
SET k=1
IF $DATA(mresult(k))=0 {WRITE "no dictionary matches for this source",!}
ELSE {
WHILE $DATA(mresult(k)) {
WRITE $PIECE($LISTTOSTRING(mresult(k)),",",2)," "
WRITE $PIECE($LISTTOSTRING(mresult(k)),",",4)
WRITE " matches: ",$PIECE($LISTTOSTRING(mresult(k)),",",6)
WRITE " score: ",$PIECE($LISTTOSTRING(mresult(k)),",",7),!
SET k=k+1 }
}
SET srcname=$PIECE($PIECE(extId,":",3,4),"\",$l(extId,"\"))
WRITE "End of ",srcname," match items for dictionary ",dictId,!!
}
GetMatchesBySource()Opens in a new tab メソッドは、各ソースをディクショナリとマッチングさせて、一致した項目を返します。
以下の例では、ドメイン内の全ソースをドメイン固有の AviationTermsND ディクショナリ (上記にて定義) とマッチングさせて、各ソースの一致項目を一致スコアおよび否定 (存在する場合) 付きで返します。
DomainCreateOrOpen
SET dname="mydomain"
IF (##class(%iKnow.Domain).NameIndexExists(dname))
{ SET domoref=##class(%iKnow.Domain).NameIndexOpen(dname)
GOTO DeleteOldData }
ELSE
{ SET domoref=##class(%iKnow.Domain).%New(dname)
DO domoref.%Save()
GOTO ListerAndLoader }
DeleteOldData
SET stat=domoref.DropData()
IF stat { GOTO ListerAndLoader }
ELSE { WRITE "DropData error ",$System.Status.DisplayError(stat)
QUIT}
ListerAndLoader
SET domId=domoref.Id
SET flister=##class(%iKnow.Source.SQL.Lister).%New(domId)
SET myloader=##class(%iKnow.Source.Loader).%New(domId)
QueryBuild
SET myquery="SELECT Top 10 ID AS UniqueVal,Type,NarrativeFull FROM Aviation.Event"
SET idfld="UniqueVal"
SET grpfld="Type"
SET dataflds=$LB("NarrativeFull")
UseLister
SET stat=flister.AddListToBatch(myquery,idfld,grpfld,dataflds)
IF stat '= 1 {WRITE "The lister failed: ",$System.Status.DisplayError(stat) QUIT }
UseLoader
SET stat=myloader.ProcessBatch()
IF stat '= 1 {WRITE "The loader failed: ",$System.Status.DisplayError(stat) QUIT }
DoMatching
SET dictId=-^mydictId
FOR j=1:1:10 {SET extId=##class(%iKnow.Queries.SourceAPI).GetExternalId(domId,j)
SET stat=##class(%iKnow.Matching.MatchingAPI).GetMatchesBySource(.num,domId,extId,$LB(dictId))
IF stat'=1 {WRITE "get matches status is:",$System.Status.DisplayError(stat),!
QUIT }
WRITE "The matches are:",!
SET k=1
WHILE $DATA(num(k)) {
IF $LISTGET(num(k),15)>0 {WRITE "neg. "}
WRITE "match ",k,": ditem ",$LISTGET(num(k),4),
" dterm ",$LISTGET(num(k),5),
" matchscore ",$LISTGET(num(k),8),!
SET k=k+1 }
WRITE !,"Next Source",!
}
WRITE "End of match items for dictionary ",dictId,!
マッチング・プロファイルの定義
ディクショナリ用語とソース・テキストのユニットが一致するかどうかは、%iKnow.Matching.MatchingProfileOpens in a new tab のマッチング・プロファイル・プロパティで決まります。8 個のプロパティがあり、これらが連携して、一致かどうかを判断します。これらのプロパティはすべて、適切な既定値を使用します。既定では、すべてのディクショナリに既定のマッチング・プロファイルが割り当てられます。
既定とは異なる値を持ったプロパティを 1 つまたは複数有するカスタム・マッチング・プロファイルを作成できます。さらに、このカスタム・マッチング・プロファイルをディクショナリに割り当てることができます。カスタム・マッチング・プロファイルで指定されないすべてのプロパティには既定の値が取得されます。カスタム・マッチング・プロファイルを作成する数には制限がありません。同じマッチング・プロファイルを複数のディクショナリに適用できます。マッチング・プロファイルは、1 つのドメインに特定するか、またはネームスペースのすべてのドメインで使用できるように定義できます。
以下の例では、3 つのカスタム・マッチング・プロファイルを作成しています。1 番目はドメイン固有のもので、オプションのマッチング・プロファイル名を指定しています。NLP では、それに正の整数の ID を割り当てます。2 番目と 3 番目はネームスペースの全ドメインに対して有効です。NLP では、それぞれに負の整数の ID を割り当てます。3 番目ではオプションのマッチング・プロファイル名を指定しているので、ドメイン ID パラメータのプレースホルダとして 0 を指定する必要があります。
SET domn="mydomain"
IF (##class(%iKnow.Domain).NameIndexExists(domn))
{ SET domo=##class(%iKnow.Domain).NameIndexOpen(domn)
SET domId=domo.Id
}
ELSE {
SET domo=##class(%iKnow.Domain).%New(domn)
DO domo.%Save()
SET domId=domo.Id }
MatchingProfile
SET domprof=##class(%iKnow.Matching.MatchingProfile).%New(domId,"mydomainCMP")
WRITE "profile Id=",domprof.ProfileId,!
WRITE "profile domain=",domprof.DomainId,!
WRITE "profile name=",domprof.Name,!!
SET allprof1=##class(%iKnow.Matching.MatchingProfile).%New()
WRITE "profile Id=",allprof1.ProfileId,!
WRITE "profile domain=",allprof1.DomainId,!
WRITE "profile name=",allprof1.Name,!!
SET allprof2=##class(%iKnow.Matching.MatchingProfile).%New(0,"namespaceCMP")
WRITE "profile Id=",allprof2.ProfileId,!
WRITE "profile domain=",allprof2.DomainId,!
WRITE "profile name=",allprof2.Name
以下の例は、カスタム・マッチング・プロファイルを定義して、ディクショナリに割り当てる方法を示しています。ここでは、カスタム・マッチング・プロファイル・インスタンス oref (ここでは、customprofile) を CreateDictionary() メソッドに指定して、既定値をオーバーライドします。
#include %IKPublic
SET domn="mydomain"
IF (##class(%iKnow.Domain).NameIndexExists(domn))
{ SET domo=##class(%iKnow.Domain).NameIndexOpen(domn)
SET domId=domo.Id
}
ELSE {
SET domo=##class(%iKnow.Domain).%New(domn)
DO domo.%Save()
SET domId=domo.Id }
CustomizeMatchingProfile
SET customprofile=##class(%iKnow.Matching.MatchingProfile).%New()
WRITE "MinimalMatchScore initial value=",customprofile.MinimalMatchScore,!
SET customprofile.MinimalMatchScore=".4"
WRITE "MinimalMatchScore custom value=",customprofile.MinimalMatchScore,!
CreateDictionary
SET dictId=##class(%iKnow.Matching.DictionaryAPI).CreateDictionary(domId,"mydict","","en",customprofile)
WRITE "created a dictionary with ID=",dictId,!!
/* . . . */
CleanUpForNextTime
SET stat=##class(%iKnow.Matching.DictionaryAPI).DropDictionary(domId,dictId)
IF stat {WRITE "Dropped the dictionary"}
ELSE {WRITE "DropDictionary error",$System.Status.DisplayError(stat)}
マッチング・プロファイル・プロパティ
ディクショナリとソース・テキストのユニットの用語が一致するかどうかは、カスタム・マッチング・プロファイルで定義したマッチング・プロファイル・プロパティの値で決定されます。このプロパティによって、各ユニットのテキストの一致スコアと、一致としてレポートされる最小一致スコアを指定するしきい値が決定されます。ディクショナリのコンテンツは使用事例に応じて異なる傾向があるため、ディクショナリのマッチング・プロファイル・プロパティを 1 つまたは複数カスタマイズすることが必要な場合もあります。これらのプロパティのいずれかを変更すると、レポートされる一致の数が大幅に変化する可能性があります。したがって、全体のデータセットにディクショナリをマッチングするマッチング・プロパティを登録する前に、小さなサブセットのデータによるテストでプロパティ値の変更を試しておくことが必要な場合もあります。
%iKnow.Matching.MatchingProfileOpens in a new tab のプロパティの意味については、クラス・ドキュメントで説明されています。
MinimalMatchScore
調整用の最も一般的なマッチング・プロファイル・プロパティは MinimalMatchScoreOpens in a new tab です。このプロパティ値は、保存される一致の下限のしきい値です。これは、1 (保存された完全一致のみ) と 0 (保存された一致の可能性があるものすべて) の間の小数値で設定可能で、既定値は 0.33 です。
-
このプロパティの値を増加させることで、一致候補の数が多すぎる場合は、低質の一致をフィルタで除外できます。ディクショナリがかなり一般的で、多くの一般用語を含む場合は、これが適切だと思われます。これらの一般用語のいくつかに対して非常に近い一致が起こる CRC およびパスのみをレポートさせることが必要な場合もあります。
-
このプロパティの値を低下させることで、一致候補の数を増やすことができます。ディクショナリが非常に特殊で、常にフラグの設定が必要な重要用語のみで構成されている場合は、これが適切だと思われます。一致が緩やかではあるが重要で、それを見逃すことがないように、技術用語のディクショナリで緩やかに一致する CRC およびパスのレポートが必要な場合もあります。
MinimalMatchScore を 0 に設定すると、一致の可能性があるすべての結果が返されます。小さなサブセットのデータに新しいディクショナリをマッチングさせる作業を始める場合は、MinimalMatchScore を 0 に設定してから徐々に増加させ、フィルタによる低質な一致の除外を妥当な数の結果が得られるまで続ける作業も開始できます。
ドメインの既定マッチング・プロファイル
MAT:DefaultProfile ($$$IKPMATDEFAULTPROFILE) ドメイン・パラメータを設定することで、異なるドメイン全体に既定のマッチング・プロファイルを指定できます。(接頭辞の “MAT:” は、マッチング処理に固有のドメイン・パラメータであることを示します。)以下の例では、ドメイン固有のカスタム・マッチング・プロファイルを定義した後に、mydomain ドメインの既定マッチング・プロファイルとしてその定義済プロファイルを割り当てます。
#include %IKPublic
DomainCreateOrOpen
SET dname="mydomain"
IF (##class(%iKnow.Domain).NameIndexExists(dname))
{ SET domo=##class(%iKnow.Domain).NameIndexOpen(dname) }
ELSE
{ SET domo=##class(%iKnow.Domain).%New(dname) DO domo.%Save()}
SET domId=domo.Id
WRITE "domain ",dname," has Id ",domId,!!
CreateProfile
SET domprof=##class(%iKnow.Matching.MatchingProfile).%New(domId,"mydomainCMP")
WRITE "profile Id=",domprof.ProfileId,!
WRITE "profile domain assignment=",domprof.DomainId,!
WRITE "profile name=",domprof.Name,!
WRITE "profile properties:",!
WRITE "default MinimalMatchScore=",domprof.MinimalMatchScore,!
SET domprof.MinimalMatchScore=.27
WRITE "changed to MinimalMatchScore=",domprof.MinimalMatchScore,!!
DO domprof.%Save()
MakeProfileDomainDefault
SET str=domo.GetParameter($$$IKPMATDEFAULTPROFILE,.dpin)
WRITE "domain ",domId," DefaultProfile before SET=",dpin,!
SET sc=domo.SetParameter($$$IKPMATDEFAULTPROFILE,"mydomainCMP")
IF sc=1 {
DO domo.GetParameter($$$IKPMATDEFAULTPROFILE,.dpout)
WRITE "domain ",domId," DefaultProfile after SET=",dpout,! }
ELSE {WRITE "SetParameter error",! }
CleanUp
DO ##class(%iKnow.Domain).%DeleteId(domo.Id)
WRITE "All done"
以下の例では、ネームスペースのカスタム・マッチング・プロファイル (ドメイン固有ではない) を定義した後に、mydomain ドメインの既定マッチング・プロファイルとしてその定義済プロファイルを割り当てます。0: が SetParameter($$$IKPMATDEFAULTPROFILE,"0:nodomainCMP") のプロファイル名の前にあることに注意してください。
#include %IKPublic
DomainCreateOrOpen
SET dname="mydomain"
IF (##class(%iKnow.Domain).NameIndexExists(dname))
{ SET domo=##class(%iKnow.Domain).NameIndexOpen(dname) }
ELSE
{ SET domo=##class(%iKnow.Domain).%New(dname) DO domo.%Save()}
SET domId=domo.Id
WRITE "domain ",dname," has Id ",domId,!!
CreateProfile
SET domprof=##class(%iKnow.Matching.MatchingProfile).%New(0,"nodomainCMP")
WRITE "profile Id=",domprof.ProfileId,!
WRITE "profile domain assignment=",domprof.DomainId,!
WRITE "profile name=",domprof.Name,!
WRITE "profile properties:",!
WRITE "default MinimalMatchScore=",domprof.MinimalMatchScore,!
SET domprof.MinimalMatchScore=.27
WRITE "changed to MinimalMatchScore=",domprof.MinimalMatchScore,!!
DO domprof.%Save()
MakeProfileDomainDefault
SET str=domo.GetParameter($$$IKPMATDEFAULTPROFILE,.dpin)
WRITE "domain ",domId," DefaultProfile before SET=",dpin,!
SET sc=domo.SetParameter($$$IKPMATDEFAULTPROFILE,"0:nodomainCMP")
IF sc=1 {
DO domo.GetParameter($$$IKPMATDEFAULTPROFILE,.dpout)
WRITE "domain ",domId," DefaultProfile after SET=",dpout,! }
ELSE {WRITE "SetParameter error",! }
CleanUp
DO ##class(%iKnow.Domain).%DeleteId(domo.Id)
WRITE "All done"
また、マッチング処理に影響を与える個々のドメイン・パラメータも設定できます。
1 つの関係との一致
既定で、NLP マッチング・アルゴリズムでは、1 つの関係エンティティと一致するディクショナリ用語がスキップされます。例えば、ディクショナリ用語に "to" がある場合に、NLP では、"Pete goes to work" という文のエンティティ "goes to" との一致を試みません。この既定によって、ディクショナリが主に概念を含み、ターゲットにする場合のマッチング・パフォーマンスが最適化されます。
ただし、ディクショナリで意図的に 1 つの関係要素をターゲットにしている場合、MAT:SkipRelations ($$$IKPMATSKIPRELS) ドメイン・パラメータを 0 に設定することで、このドメイン・パラメータの既定値を変更できます。これにより、エンティティのタイプとは関係なく、すべてのエンティティがすべてのディクショナリ用語に一致するようになります。
このオプションは、マッチング・プロファイル・プロパティではなく、ドメイン・パラメータとして設定されます。その理由は、このスキップ手順は、一致した用語が何かまだわからない時点で発生し、その結果、ディクショナリ専用のどのプロファイルにも適用できないからです。したがって、これはドメイン・パラメータとして実行されることで、ドメイン内のすべてのディクショナリに確実に適用されます。
その他のマッチング処理ドメイン・パラメータ
MAT:SkipRelations、MatchScoreMargin、FullMatchOnly および EntityLevelMatchOnly など、設定可能なドメイン・パラメータのいくつかは一致処理に影響を与える可能性があります。これらのドメイン・パラメータを変更する場合は、以前のドメイン・パラメータ設定を使用して一致したソースをすべて明示的に再一致させて、新しいドメイン・パラメータ値を反映させる必要があります。
ドメイン・パラメータの詳細は、このドキュメントの付録 "ドメイン・パラメータ" を参照してください。