Git構造化辞書
Git構造化辞書は、デネブさんによって考案されている辞書形式であり、Gitオブジェクトの構造を、辞書の情報構造の表現に効果的に利用するというアイデアである。
モチベーション
発端は、以下のような辞書管理上の要請による。
辞書をバージョン管理したい
このモチベーションは自明であろう。すなわち、辞書を更新しながらも、過去の辞書へのアクセス可能性は維持したいということである。これを実現する素朴な方法の一つは、辞書をGitなどのVCSリポジトリに格納するというものである。しかし、OTM-JSONなどの巨大なシングルファイル辞書形式では、Gitの恩恵をうまく活用することができない。Gitは複数の細かいファイルを効率的に管理するようにデザインされているからである。これを解決するには、適切な単位で辞書データを複数ファイルに分解しておく必要がある。どのような単位で分解するかということには議論を要する。
情報を再利用したい
広く使われているOTM-JSONでは、単語(辞書エントリ)以外の単位で情報を再利用することができない。ピュアなJSONには、あるプロパティへの別のプロパティからの参照の機能がないため、JSONだけでこれを実現するためには、すべての値をファイル内で一意のIDと抱き合わせたオブジェクトとするか、値の中に侵襲的にJSON Pointerのような記法を導入する必要があり、あまり効率的とは言えない。これを解決するためには、JSONを使うことをやめて参照機能のあるYAMLなどを使うことになるかもしれない。再利用の問題は、次段の重複除去の問題と表裏一体である。
情報を重複除去したい
これは前段とも関係してくるが、データ間参照が使えない場合にデータを再利用しようとすると、素朴なやり方ではデータを複製して別々の位置に保持することになる。これは保守性の観点からは筋が良いとは言えず、継続的な保守を要する辞書というものの表現形式として好ましくない。したがって、可能な限りDRYを実現できるように辞書形式をデザインすべきである。
Gitでは、ディレクトリ構造はMerkle DAGとして表現されている。つまり、ユーザが何もせずとも自動的に、リポジトリに格納されたそれぞれのファイルやディレクトリにハッシュ(すなわち一意のID)が割り当てられる。このハッシュはいわゆるコンテンツハッシュ、フィンガープリントとして働いており、同じ内容のファイルやディレクトリであれば、常に同じハッシュが割り当てられる。これにより、例えばユーザが別名で全く同じ内容のファイルを追加したところで、Gitリポジトリ内部のデータは重複しないのである[1]。もちろん、この重複除去はファイルやディレクトリ単位で行われるため、先に述べた「辞書データを複数ファイルに分解しておく」ということはいっそう重要である。
情報を分散化したい
Gitは分散VCSと呼ばれているとおり、データの複製をさまざまなコンピュータに分散保持させ、参加者それぞれが独自に編集し、お互いの変更を取り入れあったり、共同で一つの(しかし実体は分散された)データを作り上げたりするためにデザインされている。この性質は辞書編集において非常に役に立つだけでなく、人間の言語運用のモデル化だと考えても非常にうまくいく。つまり、話者はそれぞれメンタルレキシコンを保持していて、そこに他者の使っている語彙を導入したり(学んだり)、他者のメンタルレキシコンに語彙を植え付けたり(教えたり)、共同のメンタルレキシコンを記述したり(標準化したり)する。
情報を永続化したい
重複除去の段で述べたハッシュ化は、データの永続化にも役に立つ。コンテンツのハッシュをコンテンツのアドレスとして用いるということは、だれがどこでいつコンテンツを保持・配信していたとしても、アドレスが等しければ常に同じコンテンツが得られるということを意味する(コンテンツアドレッシング)。これは、辞書のすべてのバージョンが、配信者のちがいや更新にしたがってその意味を変えたり失ったりしてしまわないためにも重要である。
GitHubやGitLabといった盤石なホスティングサービスがすでに存在することも、Gitを選ぶ理由の一つである。
課題
辞書構造をGitオブジェクトで表現するために、以下の課題がある。
情報をどのような単位で分解するか
意味論的単位
もっとも自然な考え方は、単語や語彙素や辞書エントリといった、人間にとって意味のある単位で分解することであろう。しかし、これにはいくつかの困難が伴う。
単語ごとにファイルを作ると聞いて、辞書編集者はまず見出し語をファイル名にすることを考えるだろう。しかし、スラッシュなどのファイルシステムによって予約された文字はファイル名には使えないので、そういった文字を書記体系や正書法、転写法に含む言語を作っている(または作りたい)場合に困ったことになる。ファイル名は常にURLエンコードされたものとする、などのトリックによってこの制約を回避することはできるが、言語によってはファイル名が人間可読ではなくなってしまう。ほんらい如何なる表記法も表現可能であるはずの人工言語という領域において、このように一部の言語に対してのみ制約があるのでは明らかに不公平であり、多言語システムとして到底許容できるものではない。
では、見出し語とは無関係の、一意のIDをファイル名にすることを考えてみよう。この場合、一つの単語ファイルを探したいときにファイラーでブラウズするというようなことは、どんな言語でもほぼ不可能になるだろう。しかし、言語によって利便性に差がついてしまうよりは確実に善良なアイデアである。このような辞書データを人間が編集するにあたって、標準のファイラーの代わりに何らかの統合開発環境のようなインターフェースが必要になるはずである。
形式的単位
もっとも細かい粒度では、辞書の情報とは①文字列片と②そのペア、そして③その集合に分解することができる。ファイルシステムのアナロジーでは、これらはそれぞれ①ファイル名や①ファイル内容と②それらの結びつき(つまりファイル)、そして③それらを含むディレクトリに対応する。これらはそれぞれGitによってハッシュ化される。ハッシュ化できるものは参照し再利用できると考えてよいので、この方法は最大限の再利用性をわれわれに授ける。
この方式を選ぶのであれば、ファイルシステムという抽象化にはほぼ意味がなくなる。というのも、この方式でGitリポジトリ上に辞書を構造化するとすれば、ファイルシステム上での「ファイル」や「ディレクトリ」といった概念が辞書上の何らかの意味論的単位に直接結びつかないからである。このような辞書データを人間が編集するあたって、やはり特別なインターフェースの用意が必要となる。
また、データサイズが必要以上に肥大化してしまうかもしれない欠点もある。たとえば、辞書におけるほとんどの文字列片のサイズは、Gitが内部で利用しているSHA-1のハッシュ長20バイトよりも小さいかもしれない。極端な話、もし辞書内のあらゆる項目から参照されているある単語が、ハッシュ化しなければもともと1バイトで済むはずの文字列片だった場合には、その部分だけ見れば20倍のサイズに膨れ上がってしまうことになり、無視できなくなってくる。
分解された情報をどのように関連づけるか
これは参照方法の問題であるが、このことは同時に、ファイル名やファイル形式の問題とも関連していることを意味する。
辞書を複数ファイルに分割するというときに、参照には以下の2種類が生まれる。
ファイル内参照
これは、先に述べた「形式的単位」よりも大きな単位でファイル分割する場合に問題になる。したがって、問題が一つ消えるという意味では、形式的単位を選ぶことに軍牌が上がると言える。
すでにリアルワールドで広く使われているYAMLなどのファイル形式が、ファイル内参照にビルトイン対応していることがある[2]。しかし、本当にそういった特定のファイル形式の仕様に依存した辞書形式にしてしまってよいのかどうかは考慮する必要がある。JSON PointerやJSONPathのような参照機能を侵襲的に埋め込む方式の利点は、本質的にはデータの論理構造がファイル形式に縛られていないという点である。いわば、YAMLのそれのようなビルトイン参照機能は(データを整理するための)メタ言語の一部であるのに対して、JSON Pointerのような参照は(データ自体がその形式をとっているところの)対象言語に埋め込まれているからである。処理効率や実装コストを考慮するのなら前者に軍牌が上がるが、データ自体の普遍性や可搬性を重視するのなら後者の方が望ましいだろう。普遍性という意味ではOTM(一対多)と似た思想にもつながる。
仮にファイル形式を選定するとして、Gitで取り扱いやすいのは、YAMLのような「行単位」でデータを記述できる形式である。Gitの差分や変更履歴は行単位で表示されるため、コロンや括弧の位置などによって履歴を混乱させない形式が望ましい。これは適切にファイルを自動整形する仕組みを作ることで解決される場合もある。
ファイル間参照
Gitが情報断片をハッシュ化するにしたがい、ファイル間参照にはそのハッシュを用いるのが妥当である。しかしながら、本当に全ての参照を一意の識別子として保持すべきかどうかには一考の余地がある。OTM-JSONでは、関連語への参照にはファイル内で一意の単語IDを用いているが、実質的にはこの水準での参照は一意である必要はなく、検索クエリとしての見出し語を保持するだけで充分なはずである。むしろ一意に確定してしまわずに検索というクッションを挟んだ方が、辞書を引くユーザーにとっては、検索結果から新たな観念連合を把握できる可能性が開かれるので、望ましいかもしれない。
ハッシュの代わりに、ハッシュへのコンテキストローカルなエイリアスを定義し、実際の参照ではそれを使う方法もある。RDFやJSON-LDでは、コンテキストごとに語彙が定義されていて、それぞれの語彙をURIで参照することによって情報を記述するという方式を採っているが、エイリアスはこれと似た方式になるだろう。
ハッシュはあらゆるリポジトリ間でコンテンツに対して一意であるために、将来的には、辞書間での参照の仕組みを構築することも理論上可能である。これにはGitのサブモジュールやサブツリー機能が活用できるかもしれない。