Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

はてなブックマークのシステムについて

14,337 views

Published on

Published in: Technology
  • Be the first to comment

はてなブックマークのシステムについて

  1. 1. はてなブックマークの システムについて 株式会社はてな / {Shibuya, Kansai}.pm 伊藤 直也
  2. 2. 自己紹介 <ul><li>株式会社はてな 執行役員 CTO </li></ul>
  3. 3. アジェンダ <ul><li>はてなブックマークのこれまでと現状 </li></ul><ul><li>各種機能の実現方法 </li></ul><ul><li>パフォーマンスに関する話 </li></ul>
  4. 4. はてなブックマークの これまでと現状
  5. 5. はてなブックマーク
  6. 6. はてなブックマークのこれまで <ul><li>2005/2 ベータ版リリース </li></ul><ul><li>2005/8 正式版リリース </li></ul><ul><li>2008/7 関連エントリー機能 </li></ul><ul><ul><li>株式会社プリファードインフラストラクチャー  (PFI) と共同開発 </li></ul></ul><ul><li>2008/11 はてなブックマーク 2 </li></ul><ul><ul><li>システムリニューアル </li></ul></ul><ul><ul><li>全文検索 (w/ PFI) 、カテゴライズ etc </li></ul></ul><ul><li>2009/4 Firefox 拡張 </li></ul><ul><li>2009/5 はてなブックマークプラス </li></ul><ul><ul><li>有料オプション </li></ul></ul>
  7. 7. 現在の数字 <ul><li>300,000 ユーザー登録 </li></ul><ul><li>400万セッション/月 (Google Analytics) </li></ul><ul><li>1,600万 URL / 4,700万 ブックマーク </li></ul>
  8. 8. データの規模の例 mysql> select count(*) from relword; +-----------+ | count(*) | +-----------+ | 351277311 | +-----------+ 1 row in set (0.00 sec)
  9. 9. データの規模 <ul><li>レコード数 </li></ul><ul><ul><li>1,600万 エントリー </li></ul></ul><ul><ul><li>4,700万 ブックマーク </li></ul></ul><ul><ul><li>5,000万 タグ </li></ul></ul><ul><li>データサイズ (MySQL MyISAM) </li></ul><ul><ul><li>エントリー 3GB </li></ul></ul><ul><ul><li>ブックマーク 5.5GB </li></ul></ul><ul><ul><li>タグ 4.8GB </li></ul></ul><ul><ul><li>HTML 200GB超 (zlib で圧縮済み) </li></ul></ul>
  10. 10. 中規模 ~ 大規模ウェブサービス <ul><li>サーバ台数 </li></ul><ul><ul><li>httpd </li></ul></ul><ul><ul><li>mysqld </li></ul></ul><ul><ul><li>そのほか </li></ul></ul><ul><li>コードの規模 </li></ul><ul><ul><li>Perl コード 10 万行弱 (WAF 等抜きで 45,000 行 ) </li></ul></ul><ul><ul><li>.pm ファイル 1,200 個強 (600 個 ) </li></ul></ul><ul><li>Google, Yahoo!, Amazon が超大規模とすると中規模くらい </li></ul><ul><ul><li>レコード数 千万件単位、データ規模は GB 単位 </li></ul></ul>
  11. 11. 開発体制 <ul><li>8名体制 </li></ul><ul><ul><li>ディレクター (マネージャ) 1名 </li></ul></ul><ul><ul><li>エンジニア 3名 +アルバイト 3名 </li></ul></ul><ul><ul><li>デザイナー 1名 +アルバイト 1名 </li></ul></ul>
  12. 12. システム構成 <ul><li>基本は LAMP </li></ul><ul><ul><li>ウェブアプリ部分はオーソドックスな構成 </li></ul></ul><ul><ul><li>Linux (Xen), Apache, MySQL, Perl </li></ul></ul><ul><li>用途によってはサブシステムあり </li></ul><ul><ul><li>検索用サーバー群 (PFI の Sedue 、自社開発の検索サーバ ) </li></ul></ul><ul><ul><li>カテゴライズサーバー </li></ul></ul><ul><ul><li>スペルミス修正サーバー </li></ul></ul><ul><ul><li>非同期タスク用に TheSchwartz </li></ul></ul><ul><ul><li>分散ファイルシステムに MogileFS </li></ul></ul><ul><ul><li>etc. </li></ul></ul>
  13. 13. プログラミング言語 <ul><li>Perl 5.8 </li></ul><ul><ul><li>mod_perl </li></ul></ul><ul><ul><li>WAF ・・・ Ridge ( 自社開発 ) </li></ul></ul><ul><ul><li>O/R マッパ ・・・ DBIx::MoCo </li></ul></ul><ul><li>JavaScript </li></ul><ul><ul><li>Ten.js ( 自社開発 ) </li></ul></ul><ul><li>C++ </li></ul><ul><ul><li>Thrift </li></ul></ul><ul><ul><li>メモリ要件、速度要求が厳しい箇所 </li></ul></ul>
  14. 14. 利用している主なソフトウェア <ul><li>Perl, JavaScript, C++ </li></ul><ul><li>LAMP, Xen </li></ul><ul><li>LVS + keepalived </li></ul><ul><ul><li>ロードバランサ </li></ul></ul><ul><li>Thrift </li></ul><ul><ul><li>多言語 RPC フレームワーク (by Facebook) </li></ul></ul><ul><li>TheSchwartz </li></ul><ul><li>MogileFS </li></ul><ul><li>Lux IO </li></ul><ul><ul><li>Key Value Store </li></ul></ul><ul><li>Squid </li></ul>
  15. 15. 各種機能の実現方法
  16. 16. 本文抽出
  17. 17. HTML::ExtractContent <ul><li>はてなブックマーク2用に開発した本文抽出モジュール </li></ul><ul><ul><li>HTML から「良い感じ」に本文テキストを抽出 </li></ul></ul><ul><ul><li>CPAN に公開済 </li></ul></ul><ul><ul><ul><li>JavaScript 版を現在開発中 </li></ul></ul></ul><ul><ul><li>サイボウズ・ラボの中谷秀洋氏の Ruby 実装を Perl に移植 </li></ul></ul><ul><li>後述の検索、カテゴライズの精度に大きく影響 </li></ul>
  18. 18. HTML::ExtractContent の仕組み <ul><li>正規表現だけで高速に </li></ul><ul><li>ヒューリスティクスで &quot; 本文らしさ &quot; を判定 </li></ul><ul><ul><li>HTML を適当なブロック要素ごとに分割 </li></ul></ul><ul><ul><li>各ブロックにスコアリング </li></ul></ul><ul><ul><ul><li>本文っぽさでスコア増 ( 句読点、テキストノードの文字列長 etc) </li></ul></ul></ul><ul><ul><ul><li>本文っぽくなさでスコア減 ( リンクばかり並んでいる etc) </li></ul></ul></ul><ul><ul><li>つながっているブロックをまとめてクラスタにする </li></ul></ul><ul><ul><ul><li>高スコアが続いたらクラスタ、低スコアが来たら切れ目 </li></ul></ul></ul><ul><ul><ul><li>ブロックスコアの合計がクラスタのスコア </li></ul></ul></ul><ul><ul><li>スコアの一番高いクラスタが本文 </li></ul></ul><ul><li>詳しくは : http://d.hatena.ne.jp/tarao/20090322#1237750634 </li></ul>
  19. 19. HTML::LayeredExtractor ( 非公開 ) <ul><li>新聞など ・・・ ExtractContent で OK </li></ul><ul><li>一部のサイト ・・・ 確実に抜き出せる別の方法 </li></ul><ul><ul><li><!-- google_ad_section_start --> </li></ul></ul><ul><ul><li>Web API </li></ul></ul><ul><ul><ul><li>ニコニコ動画、 YouTube 、 Amazon.co.jp </li></ul></ul></ul><ul><ul><li>特定サイトはルールベースに処理 </li></ul></ul><ul><ul><ul><li>自社サイト、大手サイトは XPath で、など </li></ul></ul></ul><ul><ul><li>フィードを利用 </li></ul></ul><ul><ul><li>複数試して一番良い結果を選択するメタエンジン </li></ul></ul><ul><li>Chain of Responsibility で順番に試して駄目なら ExtractContent に fallback </li></ul>
  20. 20. 全文検索機能
  21. 21. 2 つの全文検索システム <ul><li>全登録文書からの全文検索 </li></ul><ul><ul><li>PFI の Sedue </li></ul></ul><ul><li>自分のブックマークからの全文検索 </li></ul><ul><ul><li>有料オプション限定の機能 </li></ul></ul><ul><ul><li>自社開発の Perl 検索エンジン </li></ul></ul>
  22. 22. 1. 全文書からの全文検索 <ul><li>Sedue </li></ul><ul><ul><li>http://preferred.jp/sedue/ </li></ul></ul><ul><ul><li>圧縮 Suffix Arrays </li></ul></ul><ul><li>スコアリングのアルゴリズム </li></ul><ul><ul><li>よく知られた幾つかのヒューリスティクス </li></ul></ul><ul><ul><li>ブックマーク数やブックマークされた時間を加味 </li></ul></ul><ul><li>文書登録 , 更新 </li></ul><ul><ul><li>ブックマークのタイミングに合わせて TheSchwartz で </li></ul></ul><ul><ul><li>1st ブックマークから数分後には検索可能 </li></ul></ul>
  23. 23. 2. 個人のブックマークからの全文検索 <ul><li>&quot;マイブックマーク全文検索&quot; </li></ul><ul><li>Perl で独自の全文検索システムを開発 </li></ul><ul><ul><li>オーソドックスな転置インデックス方式 </li></ul></ul><ul><ul><ul><li>ユーザー毎にインデックスを構築 </li></ul></ul></ul><ul><ul><li>動的に更新可能 </li></ul></ul><ul><ul><li>id:naoya プロトタイプ -> id:r_kurain ( 倉井龍太郎 ), id:tarao が中心に開発 </li></ul></ul>
  24. 24. 転置インデックス <ul><li>辞書 -> 含む文書のID 列 (Postings List) の索引 </li></ul>... perl => [1, 5, 20, 333, 350, 362 ...] python => [8, 10, 11, 52 ...] ruby => [1, 10, 21, 333, 350, 428 ...] ...
  25. 25. 転置インデックスの構成 <ul><li>二つのインデックス </li></ul><ul><ul><li>辞書が N-gram のインデックス </li></ul></ul><ul><ul><ul><li>ノイズが少なく、且つ検索漏れして欲しくないデータ用のインデックス </li></ul></ul></ul><ul><ul><ul><li>タイトル、コメント、タグ、 URL 文字列など </li></ul></ul></ul><ul><ul><li>辞書が形態素解析のインデックス </li></ul></ul><ul><ul><ul><li>本文テキスト (by ExtractContent) などノイズの多い箇所 </li></ul></ul></ul><ul><ul><ul><li>MeCab ( はてなキーワード + MeCab 辞書 ) </li></ul></ul></ul><ul><ul><li>検索は両者から行って、結果をマージ </li></ul></ul><ul><li>Postings List には文書 ID と単語出現位置を記録 </li></ul><ul><ul><li>スニペットの表示やスコアリングに出現位置が必要 </li></ul></ul><ul><ul><li>[ 10: 2, 100, 108, ... ] </li></ul></ul>
  26. 26. 転置インデックスの構成 ( 続き ) <ul><li>転置インデックスの圧縮 </li></ul><ul><ul><li>Postings List の差分を取って VB 符号 ( 相当 ) </li></ul></ul><ul><ul><li>Array::Gap </li></ul></ul><ul><ul><ul><li>http://d.hatena.ne.jp/naoya/20080906/1220685978 </li></ul></ul></ul><ul><li>転置インデックスの保存に Lux IO </li></ul><ul><ul><li>Lux の KVS </li></ul></ul><ul><ul><li>Perl バインディング Lux::IO (id:antipop) </li></ul></ul><ul><ul><li>シンプルで高速 </li></ul></ul><ul><ul><li>ユーザー毎にファイルひとつ。本システムの運用に最適 </li></ul></ul><ul><ul><ul><li>索引を作り直したかったらファイルを削除して再構築 </li></ul></ul></ul><ul><ul><ul><li>分散したいなら、ユーザー ID などでパーティショニング </li></ul></ul></ul>
  27. 27. 検索結果のスコアリング <ul><li>本夏のインターンシップで開発 </li></ul><ul><ul><li>id:yaotti, id:nyanp </li></ul></ul>
  28. 28. スコアリングの手法 <ul><li>複数のヒューリスティクスの結果を重み付き線形和で </li></ul><ul><ul><li>(例) Score = 0.5 * TF-IDF + 0.2 * ブクマ数 + 0.3 * 新鮮度 </li></ul></ul><ul><ul><li>重みは適当 </li></ul></ul><ul><ul><ul><li>本格的にやるなら正解データからの機械学習 </li></ul></ul></ul>
  29. 29. スコアリングの手法の一部 ( 続き ) <ul><li>クエリがタイトル等に含まれているかどうか </li></ul><ul><li>複数クエリ語の近傍度 </li></ul><ul><li>クエリの出現位置 ・・・ 前半であるほど良 </li></ul><ul><li>クエリのマッチの仕方 ( 単語境界かどうか etc) </li></ul><ul><li>TF-IDF </li></ul><ul><li>ブックマーク数 </li></ul><ul><li>文書の新鮮度 </li></ul><ul><ul><li>文書の 1st ブックマーク日時 </li></ul></ul><ul><li>特定の URL にボーナス </li></ul><ul><ul><li>Wikipedia, d.hatena.ne.jp/keyword など </li></ul></ul><ul><ul><li>ルートドキュメント </li></ul></ul>
  30. 30. スコアリング今後 <ul><li>PageRank や HITS 的なリンク解析 </li></ul><ul><li>クリックストリームからのフィードバック学習 </li></ul>
  31. 31. 検索エンジンとアプリケーションのやりとり <ul><li>JSON-RPC で Web API </li></ul><ul><ul><li>アクセス制限などはウェブアプリケーション側で </li></ul></ul><ul><ul><li>検索システムはあくまで検索結果を返すだけに専念 </li></ul></ul><ul><li>Web API は一般にも公開 </li></ul><ul><ul><li>google &quot;マイブックマーク全文検索API&quot; </li></ul></ul>
  32. 32. Firefox 拡張 + マイブックマーク検索 <ul><li>拡張から Web API で検索結果を取得 </li></ul>
  33. 33. スペルミス修正機能 <ul><li>もしかして </li></ul>
  34. 34. スペルミス修正サーバー <ul><li>クエリ語に対して修正候補を返す </li></ul><ul><li>C++ と Perl ・・・ Thrift </li></ul><ul><ul><li>スコアリングエンジンを C++ で、問い合わせは Perl で </li></ul></ul><ul><li>スペルミス修正のアルゴリズム </li></ul><ul><ul><li>はてなキーワードを辞書に補正 </li></ul></ul><ul><ul><li>N-gram 索引を使って候補を絞り、 Jaro-Winkler 距離 ( 編集距離のようなもの ) で近似度を測定 </li></ul></ul><ul><ul><li>詳しくは google &quot;Kansai.pm スペルミス &quot; </li></ul></ul>
  35. 35. 関連エントリー機能
  36. 36. レコメンドエンジン BSim <ul><li>PFI のレコメンドエンジン </li></ul><ul><ul><li>ブックマークのタグを入力 </li></ul></ul><ul><ul><ul><li>ほかも幾つか試したがタグの精度が圧倒的に良かった </li></ul></ul></ul><ul><ul><ul><li>タグは記事推薦に非常に有効 </li></ul></ul></ul><ul><li>Perl とのやりとり </li></ul><ul><ul><li>C++ で書かれたエンジンと Perl アプリ </li></ul></ul><ul><ul><li>Thrift を利用して RPC で </li></ul></ul>
  37. 37. カテゴライズ機能
  38. 38. 文書分類エンジン BDog <ul><li>自社開発の文書分類エンジン </li></ul><ul><ul><li>C++ で実装、 Thfirt で Perl から利用 </li></ul></ul><ul><li>本文テキスト (by ExtractContent) から単語ベクトルを作って判定 </li></ul><ul><li>ベイジアンフィルタ </li></ul><ul><ul><li>Complement Naive Bayes </li></ul></ul><ul><ul><ul><li>http://d.hatena.ne.jp/tkng/20081217/1229475900 </li></ul></ul></ul><ul><ul><ul><li>特定のクラスに偏りがある場合、 Naive Bayes よりも精度が向上 </li></ul></ul></ul><ul><ul><li>動的な学習により精度向上 </li></ul></ul><ul><ul><ul><li>ユーザーによるカテゴリ修正で ... 過学習防止のため対象は特定ユーザーに限定 </li></ul></ul></ul>
  39. 39. Complement Naive Bayes
  40. 40. そのほか <ul><li>ブックマークスパム判定機能 </li></ul><ul><ul><li>複数のルールベースを組合わせた判定エンジン </li></ul></ul><ul><ul><ul><li>例: 同一順で同一エントリをブックマークし続ける複数アカウントによるブックマーク </li></ul></ul></ul><ul><li>特徴語抽出 </li></ul><ul><ul><li>はてなキーワード </li></ul></ul><ul><ul><li>TF-IDF </li></ul></ul><ul><ul><li>関連広告表示などにも利用 </li></ul></ul>
  41. 41. 各所で TheSchwartz を活用 <ul><li>TheSchwartz </li></ul><ul><ul><li>Six Apart 社開発のジョブキューフレームワーク </li></ul></ul><ul><ul><li>CPAN </li></ul></ul><ul><li>検索、スパム判定などブックマーク追加後に各種更新処理が発生 </li></ul><ul><ul><li>同期処理だとユーザーを待たせる </li></ul></ul><ul><ul><li>TheSchwartz で非同期化 </li></ul></ul><ul><ul><ul><li>HTML を取得し本文抽出 / スパム判定 / カテゴリ判定 / Sedue への更新要求 / マイブックマーク検索エンジンへの更新要求 / はてなキーワード抽出 / リンク抽出 / favicon を取得 / AccountDiscovery / スクリーンショット撮影 ... </li></ul></ul></ul>
  42. 42. はてなブックマーク Firefox 拡張
  43. 43. Firefox 拡張 <ul><li>Firefox Add-ons </li></ul><ul><ul><li>XUL </li></ul></ul><ul><ul><ul><li>http://subtech.g.hatena.ne.jp/secondlife/20090402/1238661633 </li></ul></ul></ul><ul><ul><li>id:secondlife, id:nanto_vi が中心に開発 </li></ul></ul><ul><ul><li>オープンソース </li></ul></ul><ul><ul><ul><li>http://github.com/hatena/hatena-bookmark-xul </li></ul></ul></ul><ul><li>はてなブックマークの各種機能を JSON API にして、 Firefox から利用 </li></ul><ul><ul><li>拡張用に追加した API の一部は公開 API としてもリリース </li></ul></ul>
  44. 44. 雑感 <ul><li>Web + DB システムの一歩外の開発をここ一年ぐらいで色々した </li></ul><ul><ul><li>検索、レコメンド、Firefox拡張 ... </li></ul></ul><ul><ul><li>なかなか楽しい </li></ul></ul><ul><ul><li>新しい体験をエンドユーザーに提供できる </li></ul></ul>
  45. 45. パフォーマンスに関する話
  46. 46. バックエンドのシステム構成 <ul><li>定番の三層構造 </li></ul><ul><ul><li>LVS + KeepAlived で分散 </li></ul></ul><ul><ul><li>lighttpd or Apache -> (Squid ->) mod_perl -> MySQL </li></ul></ul>
  47. 47. バックエンドシステムの三層構造 proxy proxy LB LB app server app server app server app server LB DB DB LB LB LB
  48. 48. ハードウェア : 自作サーバー
  49. 49. データベースの構成 <ul><li>オーソドックスな構成でスケーリング </li></ul><ul><ul><li>MySQL (MyISAM) </li></ul></ul><ul><ul><ul><li>メモリ 16GB </li></ul></ul></ul><ul><ul><ul><li>一部で SSD を試験 </li></ul></ul></ul><ul><ul><li>マスタ・スレーブ構成 </li></ul></ul><ul><ul><li>データのサイズ、用途に合わせてテーブル単位で分割 </li></ul></ul><ul><ul><ul><li>メイン (ユーザ情報、エントリ、ブックマーク) </li></ul></ul></ul><ul><ul><ul><li>タグ、キーワード </li></ul></ul></ul><ul><ul><ul><li>HTMLデータ etc. </li></ul></ul></ul>
  50. 50. 島分け proxy AP bot / feed 通常のリクエスト DB 画像 API etc. proxy
  51. 51. Squid によるキャッシュ <ul><li>Squid Reverse Proxy でキャッシュ </li></ul><ul><ul><li>ゲスト向けコンテンツ </li></ul></ul><ul><ul><li>bot 向けコンテンツ </li></ul></ul><ul><ul><li>一部の API </li></ul></ul><ul><ul><ul><li>○○ users 画像のバックエンドの API など </li></ul></ul></ul>
  52. 52. memcached によるキャッシュ <ul><li>アプリケーションフレームワークに memcached キャッシュ機能 </li></ul><ul><ul><li>ページを丸ごと memcached にキャッシュする機能 </li></ul></ul><ul><ul><li>ユーザー毎の設定パラメータをまとめて SHA1 キーを作り、同じ設定のユーザーには同じキャッシュを返す機能 </li></ul></ul><ul><li>Template::Plugin::Cache </li></ul><ul><li>longtail はキャッシュしない </li></ul><ul><ul><li>○○ users を閾値に </li></ul></ul>
  53. 53. クライアント表示に関する工夫 <ul><li>昨今では定番の手法を実施 </li></ul><ul><ul><li>gzip 圧縮 </li></ul></ul><ul><ul><li>静的ファイルの Expires を 1年に </li></ul></ul><ul><ul><ul><li>更新される可能性のあるものは別ディレクトリで管理 </li></ul></ul></ul><ul><ul><ul><li>CSS, JavaScript ファイルは git の commit + path の SHA1 をクエリパラメータに </li></ul></ul></ul><ul><ul><ul><ul><li>例: /js/foo.js?sha1hogehoge </li></ul></ul></ul></ul><ul><ul><li>静的ファイルを別ドメイン -> Cookie 分の転送を削減 </li></ul></ul>
  54. 54. クライアント表示に関する工夫 ( 続き ) <ul><li>JavaScript による遅延ロード </li></ul><ul><ul><li>広告の遅延ロード </li></ul></ul><ul><ul><ul><li>広告表示でページ表示が待たされない </li></ul></ul></ul><ul><ul><ul><li>Google の広告、自社広告 </li></ul></ul></ul>
  55. 55. クライアント表示に関する工夫 ( 続き ) <ul><li>ユーザー毎に出し分ける部分を JS で遅延 </li></ul><ul><ul><li>残った共通部分 (HTML) をキャッシュできる </li></ul></ul>
  56. 56. 雑感 <ul><li>一般的な Web + DB システムの運用は苦労が減った </li></ul><ul><ul><li>ハードウェアの進歩、特にメモリ容量 </li></ul></ul><ul><ul><li>各種ノウハウがウェブや書籍等で公開されている </li></ul></ul><ul><li>JavaScript の遅延ロードをうまく使うと高速化に寄与できる箇所が多い </li></ul><ul><li>RDBMS だけでは難しい規模 / 要件をどうするかが面白い </li></ul><ul><ul><li>検索エンジンを作る、レコメンドエンジンを作る、文書分類エンジンを作る ... etc. </li></ul></ul>
  57. 57. WEB+DB PRESS Vol.49
  58. 58. まとめ <ul><li>はてなブックマークのシステムの裏側を紹介した </li></ul><ul><li>オーソドックスな Web + DB システムと幾つかのサブシステムを開発した </li></ul><ul><ul><li>検索、レコメンド、文書分類 etc </li></ul></ul><ul><li>RDBMS では難しい/面倒なことをどう解決していくかが今後もテーマに </li></ul>
  59. 59. Thank You !

×