# データモデリング ## ER図 ```mermaid erDiagram users { string username "preferredUsername" string name "表示名" string bio string icon datetime createdAt datetime updatedAt } posts { string id string inReplyTo string body number likes number shares SS to SS cc datetime createdAt datetime updatedAt } revisions { string postId string body datetime updatedAt } liked { string objectId datetime createdAt } shares { string objectId datetime createdAt } replies { string postId string objectId datetime createdAt } likes { string postId string actorId datetime createdAt } followings { string actorId datetime createdAt } subscribers { string actorId datetime createdAt } timeline { string objectId datetime when } tombstones { string objectId string formerType datetime deletedAt } users 1 -- 0+ posts : has users 1 -- 0+ liked : has users 1 -- 0+ shares : has users 1 -- 0+ followings : has users 1 -- 0+ subscribers : has users 1 -- 0+ timeline : has posts 1 -- 0+ likes : has posts 1 -- 0+ replies : has posts 1 -- 0+ revisions : has ``` - 便宜上 user**s** として関係も描いているが、存在するuserは1人だけであり、関係は暗黙に存在する - usernameは便宜上 `me` で固定する: `@me@{domain}` - tombstonesは、削除した「独り言」をtombstoneオブジェクトに置き換えるために利用する - postsのidを引いて、なかったときにtombstonesを引いて、あればtombstone、なければnot found、とする - posts のid(またはpostId)には、ローカルなID部分のみを格納する(対外的には `https://{domain}/.../{postId}` のように変換してグローバルなURI(IRI)にする) - actorId, objectIdには、グローバルなID(URI(IRI))をそのまま格納する - 「独り言」の編集 - revisionをもたせる - revisionなし → 最新版 - revisionあり → そのバージョン - 編集するときは、現在の「最新版」をrevisionを付けてコピーして、revisionなしの方を更新する ## (Dynamo)DB設計 ### メインデータ | | PK : S | SK : S | ctime : S | mtime : S | LSI1 : S | s1 : S | s2 : S | s3 : S | n1 : N | n2 : N | n3 : N | ss1 : SS | ss2 : SS | | ----------- | -------------- | ---------- | ------------ | ---------- | ---------- | ---------- | ------ | --------- | ------ | ------- | -------- | -------- | -------- | | user(s) | `ME` | | 作成日時 | 更新日時 | | name | bio | icon | | posts | `P#HHHHH` | UUID v7 | 投稿日時 | (更新日時) | | summary | body | inReplyTo | #likes | #shares | #replies | to | cc | | revisions | `P#{postId}#V` | revision | 更新日時 | | | summary | body | | | replies | `P#{postId}#R` | object URI | された日時 | | | | | | | | | | | | likes | `P#{postId}#L` | actor URI | された日時 | | shares | `P#{postId}#S` | actor URI | された日時 | | | liked | `L#HHHHH` | object URI | した日時 | | | shared | `S#HHHHH` | object URI | した日時 | | | followings | `F` | actor URI | した日時 | | subscribers | `SUB` | actor URI | された日時 | | timeline | `TL#HHHHH` | 日時 | | | object URI | | | tombstones | `D` | object URI | 削除した日時 | | | formerType | * `HHHHH`には、UNIX時間を16進数表示した(UUID v7の)上位5文字を含める。[メモ「postsのPK」を参照](#postsのpk) * timelineは基本的に挿入日時でソートすれば良いが、Deleteアクティビティに備えてオブジェクトのURIで検索できるようにLSIを作成する。 ### 連合用データ | | PK : S | SK | expires : N | s1 : S | s2 : S | json : Map | | ------- | ---------------- | ----------- | ----------- | ------------- | ------ | ---------- | | objects | `O#{object URI}` | | +_max-age_ | | | object | | servers | `S#{hostname}` | | +_max-age_ | lrdd template | | actors | `A#{acct}` | | +_max-age_ | | | actor | | actors | `A#{acct}` | `pubkey` | +_max-age_ | publicKeyPem | | | | actors | `A#{acct}` | `webfinger` | +_max-age_ | type | href | ## メモ * foreignObjectsには、actorIdやobjectIdに対応する、他サーバのActorやNoteオブジェクトをキャッシュしておく * 参照したときになければ、URI(IRI)にアクセスしてオリジナルを取りに行く * Amazon S3やCloudflare R2にJSONをファイルとして置いておくようにしても良さそう ### postsのPK LSIを入れる場合、パーティションキーの1つの値毎に10 GBまでのデータしか入らない。 そうでなくてもパーティションは分かれるようにするのが良さそう。 非常に大雑把に1投稿あたり1 MBになるとすると、パーティションキーあたり10,000件。 UUID v7なら時系列順にソートできるので、UNIX時間の一部となる先頭何文字かをprefixとしてPKに含めれば、使い勝手をあまり損ねずに分割できそう。 ```console $ printf '%d\n' 0x065400000 | xargs -r -I{} date -d @{} Tue Oct 31 04:12:00 JST 2023 $ printf '%d\n' 0x065410000 | xargs -r -I{} date -d @{} Tue Oct 31 22:24:16 JST 2023 $ printf '%d\n' 0x065411b07 | xargs -r -I{} date -d @{} Wed Nov 1 00:19:35 JST 2023 $ printf '%d\n' 0x065420000 | xargs -r -I{} date -d @{} Wed Nov 1 16:36:32 JST 2023 $ printf '%d\n' 0x065500000 | xargs -r -I{} date -d @{} Sun Nov 12 07:28:16 JST 2023 $ printf '%d\n' 0x065600000 | xargs -r -I{} date -d @{} Fri Nov 24 10:44:32 JST 2023 $ printf '%d\n' 0x066000000 | xargs -r -I{} date -d @{} Sun Mar 24 19:27:12 JST 2024 ``` こんな感じなので、5桁あれば約18時間確保できる。 18時間に10,000件投稿できるので、約6秒あたり1件は投稿できる計算になる。そんなにやらないだろう。 ### timelineのPK timelineはオブジェクトIDだけで良いので1件1 KBとして、パーティションキーあたり10,000,000件。 件数的にはあまり分けなくて良さそうだが、postsと合わせておく。 取得できる時間の範囲を揃えておくと都合が良さそう。