wikiデータを利用したサービスを開発しているですが、その際に直面した問題と解決方法です。
【問題】
wikiデータのファイルが3GBを超えるサイズで、ここから指定したキーワードのみを高速でデータ抽出行い、DBに保存したい。
【解決方法】
まず、wikiデータ(wiki.dat)からtitleタグの付いたデータを
% grep -b ‘<title>’ wiki.dat > title.dat
としてタイトルのみのindexファイル(title.dat)を作成する。
— title.datの中身 —
…..
3065193478: <title>ヴァルメト</title>
3065196091: <title>鮨勘</title>
3065196442: <title>クロックマダム</title>
3065197671: <title>八木麻紗子</title>
3065200143: <title>イチロー</title>
…..
“:”をセパレータとした1フィールド目がfseekでのオフセット値になる。
キーワードリスト(keyword.txt)からデータを読み取りwiki説明データを抽出するプログラムサンプルは下記の通り。
—- サンプルソース —
#!/usr/local/bin/php -q <?php ini_set("display_errors", 1); { $lines = file("keyword.txt"); foreach($lines as $line){ $keyword = trim($line); $offset = checkExist($keyword); if (!$offset){ continue; // not exists. } print getWiki($keyword, $offset); } } function checkExist($keyword) { if (!$keyword){ return; } $cmd = "grep '<title>$keyword</title>' title2.dat"; $line = `$cmd`; if (!$line){ return 0; } list($n, $dat) = explode(":", $line); return $n; } function getWiki($keyword, $offset) { if (!$keyword){ return; } $fp = fopen("wiki.dat", "r"); $MAX = 2000000000; // ファイルサイズが2G以上だと一度にseekできない。 if ($offset > $MAX){ fseek($fp, $MAX); $offset = $offset - $MAX; } fseek($fp, $offset, SEEK_CUR); $flg = 0; $text = ""; while (!feof($fp)) { $buf = fgets($fp, 512); if (strpos($buf, "<title>$keyword</title>")){ $flg = 1; } if ($flg){ if (strpos($buf, "<text xml:")){ $flg = 2; } if ($flg == 2){ $text .= $buf; } if (strpos($buf, "</text>")){ $text = strip_tags($text); fclose($fp); return $text; } } } fclose($fp); } ?>