PHP Source Code Search
with
PHP

柄沢聡太郎 (sotarok)
http://nequal.jp/
twitter.com/sotarok
始める前に




   Copyright © nequal, Creative Commons Attribution-
                 Noncommercial 2.1 @ PHP Study #46.
今⽇はPHP勉強会




     Copyright © nequal, Creative Commons Attribution-
                   Noncommercial 2.1 @ PHP Study #46.
なぜ 9/29 ではないのか




        Copyright © nequal, Creative Commons Attribution-
                      Noncommercial 2.1 @ PHP Study #46.
懇親会はピザだって?




     Copyright © nequal, Creative Commons Attribution-
                   Noncommercial 2.1 @ PHP Study #46.
⾁はどうしたんですか




     Copyright © nequal, Creative Commons Attribution-
                   Noncommercial 2.1 @ PHP Study #46.
本来のPHP勉強会




            Copyright © nequal, Creative Commons Attribution-
                          Noncommercial 2.1 @ PHP Study #46.
PHPerは
⾁の精神を忘れ
 てしまったか
    Copyright © nequal, Creative Commons Attribution-
                  Noncommercial 2.1 @ PHP Study #46.
ごめんなさい冗談です
gusagiさん幹事おつかれさまです




         Copyright © nequal, Creative Commons Attribution-
                       Noncommercial 2.1 @ PHP Study #46.
じこしょうかい
sotarok
•   そうたろう(けー)
•   プリン
•   プリン
•   プリン
•   pudding
•   プリン
•   ⾁
•   ごはん
•   自転⾞
•   写真 – Sony α 300
•   Ethna
•   nequal
                      Copyright © nequal, Creative Commons Attribution-
                                    Noncommercial 2.1 @ PHP Study #46.
宣伝
• WikiHub
  – http://wikihub.org/
  – Git で⽂書管理して,それを Wiki 形式で整形して
    表⽰
  – GitHub の Service Hook で簡単同期
• 制限つきOpenBeta
  – 100⼈まで




                 Copyright © nequal, Creative Commons Attribution-
                               Noncommercial 2.1 @ PHP Study #46.
宣伝2                     なぜか誰も
                        買ってこない
• プリンが好きです




             Copyright © nequal, Creative Commons Attribution-
                           Noncommercial 2.1 @ PHP Study #46.
宣伝2                      yuchimiriさんに
                        RTまでされたのに

• プリンが好きです




             Copyright © nequal, Creative Commons Attribution-
                           Noncommercial 2.1 @ PHP Study #46.
検索エンジンとか
                         つくってるとこ!




 Preferred Infrastructure (PFI)
というところでインターンやってます




 だからか
        だからです
                 Copyright © nequal, Creative Commons Attribution-
                               Noncommercial 2.1 @ PHP Study #46.
Agenda
•   検索エンジン
•   転置インデックス
•   クロールとキーワード抽出
•   スコアリングと並び替え
•   デモ
•   技術的な課題とか




               Copyright © nequal, Creative Commons Attribution-
                             Noncommercial 2.1 @ PHP Study #46.
検索エンジン
• キーワードを⼊⼒
 – → そのキーワードが含まれる(そして探したいと
   思われる)⽂書が探せる

• ソースコード検索
 –   grep
 –   gtags (GNU GLOBAL)
 –   trac + Hyper Estraier (BTS + Plugin)
 –   Google Code Search


                           Copyright © nequal, Creative Commons Attribution-
                                         Noncommercial 2.1 @ PHP Study #46.
grep
• 与えられたキーワードをファイルをたどり,⽂字
  列⼀致で探す
• 前処理が必要ない
• どこにでも⼊ってる


grepのデメリット
• 大量の⽂書から探すのは時間がかかる
  – 同じキーワードで再検索するときもまた同じ処理
• ランキングづけができない

             Copyright © nequal, Creative Commons Attribution-
                           Noncommercial 2.1 @ PHP Study #46.
検索エンジンを作る
• 既存のいろんなソフトウェアを使うのもいいけど
• 「検索エンジン」
 – そんな難しくない
 – PHPでもできる
 – カンタンだよ!

• 今回の目標
 – ローカルのPHPソースファイルからメソッドや関数
   や変数を検索できるようにする
 – ディレクトリを指定して,再帰的にPHPファイルを
   検索
 – grep -rn 'substr' **/*.php

               Copyright © nequal, Creative Commons Attribution-
                             Noncommercial 2.1 @ PHP Study #46.
転置インデックス
転置インデックス
• キーワードから⽂書を逆引きできるようにあらか
  じめつくっておくインデックス

• 焼⾁ =>
  –   ⽜角
  –   Wikipedia – 焼⾁
  –   YAKINIQUEST - ヤキニクエスト
  –   ...




                     Copyright © nequal, Creative Commons Attribution-
                                   Noncommercial 2.1 @ PHP Study #46.
※⽂書はフィクションです

⽂書1
I like Sushi, Yakiniku and pudding !

⽂書2
PHPer like Yakiniku. Maybe not like
Sushi.

⽂書3
Dankogai is an enemy of PHPer.


                           Copyright © nequal, Creative Commons Attribution-
                                         Noncommercial 2.1 @ PHP Study #46.
※⽂書はフィクションです

⽂書1
I like Sushi , Yakiniku and pudding !

⽂書2
PHPer like Yakiniku. Maybe not like
Sushi.

⽂書3
Dankogai is an enemy of PHPer. He
also like Yakiniku.

                           Copyright © nequal, Creative Commons Attribution-
                                         Noncommercial 2.1 @ PHP Study #46.
Sushi          1




             ⽂書1
             I like Sushi, Yakiniku and pudding !
      ⽂書2
    PHPer like Yakiniku. Maybe not like
⽂書3 Sushi.
Dankogai is an enemy of PHPer. He
also like Yakiniku.
                           Copyright © nequal, Creative Commons Attribution-
                                         Noncommercial 2.1 @ PHP Study #46.
Sushi           1
 Yakiniku          1




             ⽂書1
             I like Sushi, Yakiniku and pudding !
      ⽂書2
    PHPer like Yakiniku. Maybe not like
⽂書3 Sushi.
Dankogai is an enemy of PHPer. He
also like Yakiniku.
                           Copyright © nequal, Creative Commons Attribution-
                                         Noncommercial 2.1 @ PHP Study #46.
Sushi           1
 Yakiniku          1
 pudding           1


             ⽂書1
             I like Sushi, Yakiniku and pudding !
      ⽂書2
    PHPer like Yakiniku. Maybe not like
⽂書3 Sushi.
Dankogai is an enemy of PHPer. He
also like Yakiniku.
                           Copyright © nequal, Creative Commons Attribution-
                                         Noncommercial 2.1 @ PHP Study #46.
Sushi           1
 Yakiniku          1              2
 pudding           1


             ⽂書1
             I like Sushi, Yakiniku and pudding !
      ⽂書2
    PHPer like Yakiniku. Maybe not like
⽂書3 Sushi.
Dankogai is an enemy of PHPer. He
also like Yakiniku.
                           Copyright © nequal, Creative Commons Attribution-
                                         Noncommercial 2.1 @ PHP Study #46.
Sushi           1              2
 Yakiniku          1              2
 pudding           1


             ⽂書1
             I like Sushi, Yakiniku and pudding !
      ⽂書2
    PHPer like Yakiniku. Maybe not like
⽂書3 Sushi.
Dankogai is an enemy of PHPer. He
also like Yakiniku.
                           Copyright © nequal, Creative Commons Attribution-
                                         Noncommercial 2.1 @ PHP Study #46.
転置インデックスをPHPで
 • array でしょJK


$inverted_index = array(
    'miyazaki' => array(1, 2, 6, 4 ...),
    'aoi' => array(2, 6, 7, ...),
    'sotarok' => array(...),
    ...
);
    配列のキー:             配列の要素:
      単語              ⽂書IDのリスト
                       Copyright © nequal, Creative Commons Attribution-
                                      Noncommercial 2.1 @ PHP Study #46.
クロールとキーワード抽出
クロールとキーワード抽出

• 対象の⽂書からキーワードを拾い集める
• クローラー -> Google なら Google Bot とか

• キーワード ->
  – 空⽩区切りの⽂字列(英語圏のひと)
  – 形態素解析(明⽇ は あめ だ)
  – n-gram
    • n⽂字区切りでキーワードにする
    • 2-gram(bi-gram)
    • 明⽇ ⽇は はあ あめ めだ

                   Copyright © nequal, Creative Commons Attribution-
                                 Noncommercial 2.1 @ PHP Study #46.
クロールとキーワード抽出をPHPで(1)


•function crawl ($dirname)
   • foreach(glob($dirname . "/*") as $file)
      • if is_dir($file):
         • $files += crawl ($file)
      • else:
         • if $file ~= /.+¥.php$/
             • $files[] = $file
   • return $files

                        Copyright © nequal, Creative Commons Attribution-
                                      Noncommercial 2.1 @ PHP Study #46.
クロールとキーワード抽出をPHPで(2)

• キーワードの抽出
   – 関数名/メソッド名/クラス名/変数名
   – tokenizer を使う

• token_get_all
   • PHP
   •         tokenize
      • http://php.net/tokenizer

• T_STRING
• T_VARIABLE
                       Copyright © nequal, Creative Commons Attribution-
                                     Noncommercial 2.1 @ PHP Study #46.
スコアリングと並び替え
スコアリングと並び替え
• なにかの基準で検索結果を並び替える
• あてはまりの良い⽂書を上に出す

• 普通の検索 なら
 – ページランク (Google のウェブ検索)
 – TF-IDF
     • ⽂書中の単語の出現頻度
     • その単語の⽂書全体での珍しさ
 – ...


                 Copyright © nequal, Creative Commons Attribution-
                               Noncommercial 2.1 @ PHP Study #46.
スコアリングと並び替えをPHPで
• スコアはソースコード中のそのキーワードの出現
  数
• 多い順に並び替え
                                PHP 5.3 なら
                             function($v1, $v2)
uasort(                          でいける!
  $scored,
  create_function(
    '$v1, $v2',
    'return $v1[¥'count¥'] < $v2[¥'count¥'];'
  )
);                      Copyright © nequal, Creative Commons Attribution-
                                      Noncommercial 2.1 @ PHP Study #46.
デモ


Hyper Pudding
http://gist.github.com/192879
技術的な課題
• デモったやつは全部 on memory
  – 大規模⽂書はイケない
    • symfony で 140MB くらい⾷うかな
  – ということで,転置インデックスを外部ファイル
    (Key-Value Store... まぁ,SQLite とかでもいい
    けど) に保持するといい
• 並び替えの基準は出現頻度でいいの?
  – これはまあ難しいですね
  – 属性情報とかいろいろとればさらに
• And/Or 検索

                     Copyright © nequal, Creative Commons Attribution-
                                   Noncommercial 2.1 @ PHP Study #46.
まとめ
• 簡単な検索エンジンはPHPでもつくれる
 – それもお⼿軽に
• インデックスをあらかじめつくっておけば検索は
  瞬時にできる
• 検索技術とか楽しい




             Copyright © nequal, Creative Commons Attribution-
                           Noncommercial 2.1 @ PHP Study #46.
ありがとうございました



Question?

PHP Source Code Search with PHP

  • 1.
    PHP Source CodeSearch with PHP 柄沢聡太郎 (sotarok) http://nequal.jp/ twitter.com/sotarok
  • 2.
    始める前に Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 3.
    今⽇はPHP勉強会 Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 4.
    なぜ 9/29 ではないのか Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 5.
    懇親会はピザだって? Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 6.
    ⾁はどうしたんですか Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 7.
    本来のPHP勉強会 Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 8.
    PHPerは ⾁の精神を忘れ てしまったか Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 9.
    ごめんなさい冗談です gusagiさん幹事おつかれさまです Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 10.
  • 11.
    sotarok • そうたろう(けー) • プリン • プリン • プリン • pudding • プリン • ⾁ • ごはん • 自転⾞ • 写真 – Sony α 300 • Ethna • nequal Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 12.
    宣伝 • WikiHub – http://wikihub.org/ – Git で⽂書管理して,それを Wiki 形式で整形して 表⽰ – GitHub の Service Hook で簡単同期 • 制限つきOpenBeta – 100⼈まで Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 13.
    宣伝2 なぜか誰も 買ってこない • プリンが好きです Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 14.
    宣伝2 yuchimiriさんに RTまでされたのに • プリンが好きです Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 15.
    検索エンジンとか つくってるとこ! Preferred Infrastructure (PFI) というところでインターンやってます だからか だからです Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 16.
    Agenda • 検索エンジン • 転置インデックス • クロールとキーワード抽出 • スコアリングと並び替え • デモ • 技術的な課題とか Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 17.
    検索エンジン • キーワードを⼊⼒ –→ そのキーワードが含まれる(そして探したいと 思われる)⽂書が探せる • ソースコード検索 – grep – gtags (GNU GLOBAL) – trac + Hyper Estraier (BTS + Plugin) – Google Code Search Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 18.
    grep • 与えられたキーワードをファイルをたどり,⽂字 列⼀致で探す • 前処理が必要ない • どこにでも⼊ってる grepのデメリット • 大量の⽂書から探すのは時間がかかる – 同じキーワードで再検索するときもまた同じ処理 • ランキングづけができない Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 19.
    検索エンジンを作る • 既存のいろんなソフトウェアを使うのもいいけど • 「検索エンジン」 – そんな難しくない – PHPでもできる – カンタンだよ! • 今回の目標 – ローカルのPHPソースファイルからメソッドや関数 や変数を検索できるようにする – ディレクトリを指定して,再帰的にPHPファイルを 検索 – grep -rn 'substr' **/*.php Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 20.
  • 21.
    転置インデックス • キーワードから⽂書を逆引きできるようにあらか じめつくっておくインデックス • 焼⾁ => – ⽜角 – Wikipedia – 焼⾁ – YAKINIQUEST - ヤキニクエスト – ... Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 22.
    ※⽂書はフィクションです ⽂書1 I like Sushi,Yakiniku and pudding ! ⽂書2 PHPer like Yakiniku. Maybe not like Sushi. ⽂書3 Dankogai is an enemy of PHPer. Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 23.
    ※⽂書はフィクションです ⽂書1 I like Sushi, Yakiniku and pudding ! ⽂書2 PHPer like Yakiniku. Maybe not like Sushi. ⽂書3 Dankogai is an enemy of PHPer. He also like Yakiniku. Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 24.
    Sushi 1 ⽂書1 I like Sushi, Yakiniku and pudding ! ⽂書2 PHPer like Yakiniku. Maybe not like ⽂書3 Sushi. Dankogai is an enemy of PHPer. He also like Yakiniku. Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 25.
    Sushi 1 Yakiniku 1 ⽂書1 I like Sushi, Yakiniku and pudding ! ⽂書2 PHPer like Yakiniku. Maybe not like ⽂書3 Sushi. Dankogai is an enemy of PHPer. He also like Yakiniku. Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 26.
    Sushi 1 Yakiniku 1 pudding 1 ⽂書1 I like Sushi, Yakiniku and pudding ! ⽂書2 PHPer like Yakiniku. Maybe not like ⽂書3 Sushi. Dankogai is an enemy of PHPer. He also like Yakiniku. Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 27.
    Sushi 1 Yakiniku 1 2 pudding 1 ⽂書1 I like Sushi, Yakiniku and pudding ! ⽂書2 PHPer like Yakiniku. Maybe not like ⽂書3 Sushi. Dankogai is an enemy of PHPer. He also like Yakiniku. Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 28.
    Sushi 1 2 Yakiniku 1 2 pudding 1 ⽂書1 I like Sushi, Yakiniku and pudding ! ⽂書2 PHPer like Yakiniku. Maybe not like ⽂書3 Sushi. Dankogai is an enemy of PHPer. He also like Yakiniku. Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 29.
    転置インデックスをPHPで • arrayでしょJK $inverted_index = array( 'miyazaki' => array(1, 2, 6, 4 ...), 'aoi' => array(2, 6, 7, ...), 'sotarok' => array(...), ... ); 配列のキー: 配列の要素: 単語 ⽂書IDのリスト Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 30.
  • 31.
    クロールとキーワード抽出 • 対象の⽂書からキーワードを拾い集める • クローラー-> Google なら Google Bot とか • キーワード -> – 空⽩区切りの⽂字列(英語圏のひと) – 形態素解析(明⽇ は あめ だ) – n-gram • n⽂字区切りでキーワードにする • 2-gram(bi-gram) • 明⽇ ⽇は はあ あめ めだ Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 32.
    クロールとキーワード抽出をPHPで(1) •function crawl ($dirname) • foreach(glob($dirname . "/*") as $file) • if is_dir($file): • $files += crawl ($file) • else: • if $file ~= /.+¥.php$/ • $files[] = $file • return $files Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 33.
    クロールとキーワード抽出をPHPで(2) • キーワードの抽出 – 関数名/メソッド名/クラス名/変数名 – tokenizer を使う • token_get_all • PHP • tokenize • http://php.net/tokenizer • T_STRING • T_VARIABLE Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 34.
  • 35.
    スコアリングと並び替え • なにかの基準で検索結果を並び替える • あてはまりの良い⽂書を上に出す •普通の検索 なら – ページランク (Google のウェブ検索) – TF-IDF • ⽂書中の単語の出現頻度 • その単語の⽂書全体での珍しさ – ... Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 36.
    スコアリングと並び替えをPHPで • スコアはソースコード中のそのキーワードの出現 数 • 多い順に並び替え PHP 5.3 なら function($v1, $v2) uasort( でいける! $scored, create_function( '$v1, $v2', 'return $v1[¥'count¥'] < $v2[¥'count¥'];' ) ); Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 37.
  • 38.
    技術的な課題 • デモったやつは全部 onmemory – 大規模⽂書はイケない • symfony で 140MB くらい⾷うかな – ということで,転置インデックスを外部ファイル (Key-Value Store... まぁ,SQLite とかでもいい けど) に保持するといい • 並び替えの基準は出現頻度でいいの? – これはまあ難しいですね – 属性情報とかいろいろとればさらに • And/Or 検索 Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 39.
    まとめ • 簡単な検索エンジンはPHPでもつくれる –それもお⼿軽に • インデックスをあらかじめつくっておけば検索は 瞬時にできる • 検索技術とか楽しい Copyright © nequal, Creative Commons Attribution- Noncommercial 2.1 @ PHP Study #46.
  • 40.