[PR]
:fish: :fish: :fish: 長文記事で疲れた目にあまねけ!水族館のまったりした癒やしをぜひ。 :tropical_fish: :tropical_fish: :tropical_fish: あまねけ!の同接で増える海のいきものが、穏やかな水槽をゆらゆら泳ぎます。 :jellyfish: :jellyfish: :jellyfish::fish: :fish: :fish: 長文記事で疲れた目にあまねけ!水族館のまったりした癒やしをぜひ。 :tropical_fish: :tropical_fish: :tropical_fish: あまねけ!の同接で増える海のいきものが、穏やかな水槽をゆらゆら泳ぎます。 :jellyfish: :jellyfish: :jellyfish:
自由な写真素材ならアマネイメージズをご利用ください。多くの写真がCC BY 4.0でライセンスされているので、経済的で利用もかんたんです。自由な写真素材ならアマネイメージズをご利用ください。多くの写真がCC BY 4.0でライセンスされているので、経済的で利用もかんたんです。
techカテゴリでは、技術的な解説記事を読むことができます。独自の視点から掘り下げた素直で分かりやすいストーリーが魅力です。techカテゴリでは、技術的な解説記事を読むことができます。独自の視点から掘り下げた素直で分かりやすいストーリーが魅力です。

icon of Amane Katagiri ははいぬ・けつあつ・くちかせ――日本語のhuman-readable nameを考える

docker run ...

Dockerでコンテナを起動するとき、 --name を与えないとランダムな英単語の組み合わせで名前が付くことはよく知られています。これはコンテナIDやUUIDのような完全にランダムな16進数ではなく、人間でも読みやすく見分けやすいIDを与える仕組みです。

$ docker run hello-world

Hello from Docker!
...

$ docker ps -a --format "table {{.ID}} {{.Names}}"
CONTAINER ID NAMES
f194dc6f87b5 wonderful_kowalevski
ff656b2992d0 kind_chaplygin
130258500f29 festive_nash
5bcc03f329fe clever_bardeen
977e200749ca hopeful_moore

この名前の生成ロジックは、namesgeneratorというパッケージで提供されています。ハードコードされた形容詞(108個)と著名人の姓(236個)から(非暗号論的な)乱数を元に1つずつ選び、 _ で接続するというシンプルな実装です。

ちなみに、このパッケージはもともと外部参照可能なpkgにあったのですが、Freeze the namesgenerator package against new additionsというPRをきっかけに単語リストが凍結されて、最終的に内部専用のinternalに移動しました。これらの単語リストのスラング的な意味合いや人物リストの評価で物議を醸す事態が長年にわたって続いており、メンテナンスの負担が高くなったことが主な理由だと、同PRや古いnamesgeneratorパッケージの説明に記されています。

dd if=/dev/random ...

さて、このような人間可読で(本来は)意味を持たない単語の組み合わせをhuman-readable nameと呼ぶことにしましょう。human-readable nameの決定には、以下の要素が必要です。

  • 1種類以上の空でない単語リスト(例: 形容詞のリストと著名人の姓のリスト)
  • 単語を結合する文字(例: _
  • 各単語リストから単語を取り出す1つ以上の位置

このうち、単語リストのインデックスを取り出す方法には大きく分けて2つあります。まずはDockerと同じく乱数プールから取り出したランダムなインデックス、もう1つは対象のデータに基づく決定的な手法です。

たとえば、あるIDと数値を持つオブジェクトにhuman-readable nameを付けるとき、JSON表現が {"key":"answer","value":42} なら必ず brilliant_jerk という名前にすることもできます。単純な実装では、SHA-256をとって前半と後半のバイトの剰余を取れば、決定的なインデックスを得られるでしょう。

human-readable nameから元のオブジェクトを計算できるわけではないので、役に立つシーンはそう多くなさそうですが、人間がバイト列の一致を視覚的に見分けるための表現としてはとても役に立ちます。

ssh-keygen -lv ...

実際のところ、human-readableといわれる名前は全ての地域や文化圏に共通の概念ではありません。冒頭のDocker出力例にあった kowalevski を一目でソフィア・コワレフスカヤのことだと理解するのは多くの日本人には難しく、これなら「不思議なソフィア」なんて文字列の方が読みやすく覚えやすいはずです。

もちろん、このような名前はASCII文字で構成するのがある種の暗黙的了解であり、human-readable nameが登場しうるほとんどの場所で安全に使えることは重要な利点です。しかし、もともとhuman-readable nameは人間が触れるインターフェースを構成する代替手段のはずでした。世界をUnicodeが支配した今となっては、既に多くの環境で問題なく扱えるとみなしても問題ないでしょう。

このようなIDの代替表現という目的をさらに広く捉えると、ASCII文字の単語の組み合わせに限らず、バイト列をさらに読みやすく置き換える表現を活用している例はたくさんあります。

秘匿性の高い通信アプリSignalにおいて、お互いに意図した相手と通信しているかを示すSafety Numbersは、16進数のハッシュを60桁の数字で表現して一致を確認しやすくする仕組みです。

OpenSSHで公開鍵のフィンガープリントを示す際に使われる二次元的なパターンも、randomartと呼ばれるhuman-readableな表現です。

+--[ED25519 256]--+
|.oB+*o..         |
| =+B *o. .       |
| .= o.+.. .      |
|   o.... .       |
|  . =o..S        |
|   +.o*.         |
| .   +o+         |
|  ooEoo          |
|+**+.o.          |
+----[SHA256]-----+

分散型の通信プロトコロルのMatrixでは、Signalと同様のMITM対策の検証としてSAS(Short Authentication String)が導入されており、対応しているクライアントでは事前に定義された64個の絵文字の組み合わせで一致を確認できます。数字の羅列よりもさらに人間の視覚に合わせた仕組みだと言えるでしょう。

MatrixクライアントのElementで検証用の絵文字が7個表示されている様子

認証の分野から離れると、what3wordsもhuman-readableな表現の重要な実装のひとつです。このサービスは、3メートル四方に区切った地図の各領域に3つの単語を与えて、位置を共有できるようにしたものです。what3wordsの位置は /// というプレフィックスで始まり、たとえば「///りゅっく。かたづけ。しぶる」のように示します。同じ位置で複数の言語にマッピングされており、英語では「///grocers.powerful.wanted」、韓国語では「///황태.늦잠.배우자」、クメール語では「///សេីច.ជាថ្មី.ត្រឹមតែ」というように、Dockerの名前生成が抱えていた文化的・言語的問題をある程度解決しています。

what3wordsで海芝浦駅の位置をスウェーデン語で示している様子

shuf -n 3 words...

さて、これらの多様なhuman-readable表現を参考に、改めて日本語のhuman-readable nameについて考えましょう。必要なのは以下の要素でした。

  • 1種類以上の空でない単語リスト
  • 単語を結合する文字

結合文字は がいいでしょう。「ははいぬ・けつあつ・くちかせ」のような感じですね。日本語ならスペース でも見栄えはいいですが、シェルやクエリで使うにはあまりに区切り文字としての意味が強すぎます。

ここまで決めれば、あとは入れ替え可能な単語リストを用意してリポジトリに含めるだけです。たとえば、単語リストが1種類なら以下でhuman-readable nameを生成できます。

$ shuf -n 3 path/to/words.txt | paste -sd '_' | sed -e 's/_/・/g'
ははいぬ・けつあつ・くちかせ

というわけで、最後に日本語の単語リストを決めましょう。この単語がhuman-readable nameの印象を大きく変えるので、丁寧に検討する必要があります。

user: ランダムな人間向けのIDを生成するのに向いた日本語の単語リストって、どこかで配布されてる?
assistant: 日本語だと...正直、ちゃんと整備された「日本語IDジェネレーター向けワードリスト」って意外と少ないんだよね😅

……えーっと、どうやって集めますか?

Dockerレベルのランダム生成で25000パターンくらいなので、2つの組み合わせなら160単語くらい必要です。でも、3つ取り出すなら30単語くらいあれば足りるでしょう。30単語を3種類用意しても90単語なので、実はあまり難しいものではありません。

ただし、過去に使ったhuman-readable nameをずっと保持する設計であれば、かなり心許ないパターン数になります。

① 赤い・青い・黄色い・きりん・ぞう...

思い付いた単語を順番に書いていくんですね! 30単語くらいなら自分で書き出したり、AIに頼むのも現実的です。

大きな
小さな
長くて
短くて
高くて
...

sample-adjective30-1.txt

大きい
小さい
長い
短い
高い
...

sample-adjective30-2.txt

犬
猫
うさぎ
ハムスター
リス
...

sample-noun30.txt

この3つを順番に並べると、こういうほのぼのコミカルなhuman-readable nameが得られます。

$ for x in $(seq 1 10); do bash -c 'shuf -n 1 sample-adjective30-1.txt; shuf -n 1 sample-adjective30-2.txt; shuf -n 1 sample-noun30.txt' | paste -sd ''; done
甘くて辛いゾウ
小さな硬いクジラ
強くて軽いリス
低くて多いシマウマ
軽くて大きい犬
重くて重いトラ
遅くて速いシマウマ
弱くて暗いサイ
明るくて柔らかいトラ
硬くて多いオオカミ

cat core_lex.csv ...

辞書から単語を取り出すんですね! こういうスクリプトでSudachi辞書から名詞や形容詞の読み仮名を取り出して、いい感じの長さの単語だけ残すと13000語くらいのひらがなを取り出せます。3つの組み合わせなら2.2兆パターンくらい使えるので、uint32で不安にならないシステムなら十分でしょう。

あいい
あいうえお
あいうち
あいお
あいか
...

sudachi-dict-hiragana-words.txt

こっちはフラットな印象のhuman-readable nameになります。

$ for x in $(seq 1 10); do shuf -n 3 sudachi-dict-hiragana-words.txt | paste -sd '_' | sed -e 's/_/・/g'; done
からたけ・おおめ・にんめん
ありったけ・せんれん・きへき
ふはつ・おりかた・いやふき
ふしのき・きほん・たっす
さくれつ・こくおう・あまちゃ
きわもの・いとよ・けいゆ
もうへい・そせい・ふみあと
きおく・さいのめ・あせかき
ふえん・ちんろん・とんか
しかい・むおん・いっく

③ さやか・ほむら・りんこ・まなか・かえで...

好きなキャラクターの名前ですか! 覚えやすくていいですね。100人くらいすぐに出てきそうですし、並べるとカップリングみたいに見えるのもいいところです。150人なら23000パターンくらいで、Docker程度のランダム性を確保できます。

あかり
ひなた
さくら
みずき
ことね
...

sample-charactors.txt

ゲームやアニメの登場人物一覧データは、だいたい有志のwikiにはよくまとまっているのですが、機械的に処理しやすいCSVやスプレッドシートなどはそう多くない印象でした。ポケモンの名前がJSONにまとまっているNode.jsライブラリpokemonはあったので、ここから取り出してもいいでしょう。

こっちは想像力が鍛えられるかもしれないhuman-readable nameになります。

$ for x in $(seq 1 10); do shuf -n 2 sample-charactors.txt | paste -sd '_' | sed -e 's/_/・/g'; done
あやね・のぞみ・なぎ
いちか・ちさと・なのか
みお・あやね・らん
らん・れん・かなで
ことね・すず・このは
なぎ・そら・かすみ
あかり・いちか・ゆい
きらら・ことね・りりか
みれい・ほのか・えみ
しずく・ももか・ちひろ

logout ...

ランダムなhuman-readable nameの生成自体は、掘り下げる余地もないシンプルな実装です。一方で、そのロジックに与える単語リストにはまだ検討の余地があります。

最近、自作のAIエージェントセッション管理システムでランダムな日本語のIDを生成しようとしたところ、使いやすい単語リストの用意になかなか手間取ってしまったので、振り返りとしてこの記事を書きました。

あなたが秘蔵している使いやすいフォーマットの日本語リストがありましたら、ぜひ私にも教えてください。

「読んだ」を押すと、あなたがボタンを押した事実を明示的に通知してこのページに戻ります。このページに戻ってからブラウザの「戻る」ボタンを押すと、何度か同じページが表示されることがあります。