自然言語分析:内部





パーサーAPI



以前の投稿を続けます。 パーサーの内部構造の詳細に集中する時間です。 実装言語としてGoを選択したのは、C ++の低レベルの深byに飛び込むことなく、低価格で(利用可能なすべてのCPUコアを使用するという意味で)生産的なツールを手に入れたいからです。



結果のコードは、次のAPIを提供します。

type Attribute struct { Name string Value string } type ParseMatch struct { Text string Nonterminal string Rule string Attributes []Attribute Submatches []ParseMatch Hypotheses []string HypothesisCount uint } func Parse(text, nonterminal string, hypotheses_limit uint) []ParseMatch
      
      





一致とは、一致規則の非端末または字句端末に対応する同じタイプの子を指します。 一般的な場合、自然言語に固有のあいまいさのために、テキストはいくつかの分析に対応します(たとえば、同音異義語の存在のため)。 したがって、 Parse関数は多くのMatchオブジェクトを返します。 上記の解析のあいまいさは、テキスト分析の次の(意味的な)レベルで解決する必要があります。



したがって、 解析関数は、 テキスト -解析するテキスト、 非終端記号 - 非終端記号の名前(たとえば、「文」)、および仮説の最大数hypotheses_limit(前の説明を参照)を取ります非終端パラメータは空かもしれません。 この場合、形態学的ベースで見つかった字句ターミナルがテキストと比較されます。



このアナライザーに関して、 仮説は、違反した属性値の制約がランダムな原因によって引き起こされているという仮定です。 アナライザーが、現在考慮されているルールで指定された制限と属性値の不一致を検出し、高度な仮説の数がhypotheses_limitに達していない場合、この不一致は無視されます。 それ以外の場合、問題のルールは破棄されます。 このメカニズムはルールのデバッグには便利ですが、解析プロセスが非常に遅くなるため、実際の作業では避ける必要があります。



非端末マッピング



このプロセスの説明に入る前に、一般的な場合、テキスト全体が比較されるのではなく、その始まりのみが比較されることに注意する価値があります。 アナライザーは、指定された非端末(またはテキストの先頭にあるすべての字句端末)に対応するテキストの可能なすべての初期部分を見つけます。



この非ターミナルの場合、アナライザーは(文法に基づいて)すべての関連ルールを抽出し、それぞれのルールへの対応を見つけようとします。 そのため、このようなルールごとに、アナライザーは属性値の割り当てをチェックします(「@ {...}」、ルールの先頭にある必要があります)。 次に、再帰関数parseRulePart呼び出され 、次のアクションを順次実行します。





字句ターミナルのマッピング



一方では、語彙端末は、単語を互いに分離する文字(スペース、コンマなど)を検索することにより、テキストから簡単に抽出できます。 一方、そのような文字を含む安定したフレーズがあります。 不可分な字句単位と見なされ、それらは異なる属性値と異なる意味さえ持つことができます(これはその後の意味解析にとって特に重要です)。 したがって、字句端末の比較は次のとおりです。





形態学的基盤



OpenCorpora Webサイトからダウンロードしたロシア語の形態学的辞書を使用します。 パーサーで使用するには、このデータを最小化し、インデックスを作成する必要があります。 最初はこの目的でSQLiteを使用しようとしましたが、結果のソリューションはパフォーマンスが不十分でした(キャッシングをオンにした後でも)。 したがって、特殊な形態学的基盤を実装する必要がありました。 測定では、検索が約9倍高速化され、初期インデックス作成が300倍高速化されました。



形態学的ベースのファイル形式はかなり単純です。ヘッダー+ 2つの大きな部分です。 最初の部分は、文字「\ 0」で区切られた単語形式で構成されています。 2番目の部分は、対応する単語形式の32ビットテキストオフセットと、32ビットにパックされたその属性の値を含む構造のソート済み配列です。 検索速度を上げるために、形態学的ベースの両方の部分がRAMに完全にロードされます。



結果のコードは、次のAPIを提供します。

 func BuildMorph(txt_filename, morph_filename string) error func InitMorph(morph_filename string) error func FinalizeMorph() func FindTerminals(prefix, separator string) []ParseMatch
      
      





FindTerminals関数は追加のセパレーターパラメーターを受け入れます。これは、安定したフレーズの場合、それが不可欠な部分であるためです。



解析キャッシュ



単語形式の検索を高速化した後でも、分析の全体的なパフォーマンスには多くの要望が残っていました(一般的な文の分析は数秒続きました)。 開発された文法の構造は、テキストと同じ非終端記号との複数の比較(多くの同様の規則の存在)を想定しているため、キャッシングの使用が示唆されました。 そのため、解析を開始する前に、 Parse関数はキャッシュ内にそのような(以前に)解析されたものがあるかどうかをチェックします。



キャッシュはハッシュテーブルに基づいているため、同時アクセスをサポートするには安全なミューテックスが必要です。 ただし、1つのグローバルミューテックスがボトルネックになる可能性があるため、キャッシュは必要な数のバンクに分割されます 。各バンクはハッシュテーブルと対応する保護ミューテキストで構成されます。



アナライザーの使用



開発したアナライザーを使用するには、次のものが必要です。




All Articles