#ツイートIDの算出
TwitterのID算出には snowflake というツールが用いられて いました (2014/5 に今後更新しない旨が GitHub のレポジトリの README に記載されています)。ただし現状もこの算出方法に基づいて ID が生成されている はず です。
twitter/snowflake
このツールの解説がありましたので、IDに付いての解説部分を引用します。
snowflakeではlong値(64bit)としてIDを表現します。実際は、unsigned long / signed long いずれの環境でも特に細工なく使用できるようにするためか、63bitの範囲で表現しているようです。
bit layoutは以下。
- timestamp(41bit) : 現在のunixtime(milliseconds)から、ある時点のunixtimeを引いた値
- machine id(10bit) : 生成器ごとに割り当てられたID
- sequence(12bit) : 生成器ごとに採番するsequence番号
ざっくり言うと、全体としての一意性はtimestampとmachine idで担保し、生成器内での一意性はsequenceで担保している、という設計になってます。
(中略)
snowflakeでは以下抜粋したコードで示すように現在日時から1288834974657を引いた値を扱っています。
その他の解説
-
Twitterのsnowflakeについて (slideshare)
上の引用では図が消えちゃったので値の配置はこちらのスライドで確認してください。
#ツイートIDから時刻を算出するtweet_id2time
メソッド
ツイートIDの算出を逆に演算すれば時刻を算出できます。
手順としては
- IDからtimestamp部分のみを切り出す。
下の22bitを落とします。すると、基準時刻からの現在時刻(ミリ秒)が求められます。 - 差っ引かれていた値を加算。
1288834974657(ミリ秒)を足してやります。 - 秒に直すために1000.0で割ります。
なお、1000で割ると整数演算になるのでミリ秒部分が落とされてしまいます。
def tweet_id2time(id)
Time.at(((id.to_i >> 22) + 1288834974657) / 1000.0)
end
##引数idのクラスをチェックするバージョン
def tweet_id2time(id)
case id
when Integer
Time.at(((id >> 22) + 1288834974657) / 1000.0)
else
nil
end
end
#実例
次のツイートの時刻を算出してみます。
このツイートのIDは481064722297397249です。@riocampos 時刻表示テスト。6/23 22:22:22。
— りおかんぽす (@riocampos) June 23, 2014
tweet_id2time(481064722297397249).strftime("%Y-%m-%d %H:%M:%S.%L %Z")
#=> "2014-06-23 22:22:22.203 JST"
ミリ秒はTime#strftime("%L")
で表示できます。
#時刻から疑似ツイートIDを作成するtime2tweet_id
メソッド
疑似ツイートIDであり、正確に言うと ミリ秒単位にみた同一時刻におけるツイートIDの下限値 です。
def time2tweet_id(time)
(time.to_f * 1000 - 1288834974657).to_i << 22
end
この疑似ツイートIDはTwitter gemのメソッドの引数に使う:since_id
の値の初期値として使うことが出来ます。メソッドとしては例えばTwitter::REST::Search#search
, Twitter::REST::Timelines#home_timeline
, Twitter::REST::Timelines#user_timeline
などが挙げられます。
#疑似ツイートIDと時刻との関係
ちなみに疑似ツイートIDtime2tweet_id(time)
と時刻time
との関係は
time2tweet_id(time)
$≦$ id
$<$ time2tweet_id(time+0.001)
$=$ time2tweet_id(time) + (1<<22)
を満たします(なお1<<22
は2**22
であり4194304)。
確認してみましょう。先ほどのツイートのID 481064722297397249 を使ってみます。tweet_id2time
メソッドを使うと、先ほどのツイートの時刻はtweet_id2time(481064722297397249)
になります。
id = 481064722297397249
time2tweet_id(tweet_id2time(id)) <= id
#=> true
id < time2tweet_id(tweet_id2time(id) + 0.001)
#=> true
time2tweet_id(tweet_id2time(id) + 0.001) == (time2tweet_id(tweet_id2time(id)) + (1<<22))
#=> true
先ほどの関係式が確かに成り立っています。