12月 4, 2008
こちらとかのエントリーを見て思ったことをつらつら
コメントに書こうとして長すぎてエントリーに。。
http://www.algoritmi.jp/seo/20081204010749.html
http://www.suzukikenichi.com/blog/googl-must-have-more-than-one-partitions/
(先にいってくと、私はGoogleもYahooも2つのインデックスは使っていないと思ってる人です)
とりあえずインデックスってどんなものなのか
イメージできていないとおもうので、
ここらへんを参考にしてみてください。
http://ja.wikipedia.org/wiki/%E8%BB%A2%E7%BD%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9
(転置インデックスの説明@wikipedia)
まあこんなかんじで
サイトがインデックスされると
ほんとに索引に近いものができるわけです。
(実際には転置インデックスはつかってないとおもいますが
イメージとして)
クロール > インデックス
ここで簡単にクロールから検索結果までのフローを書くと
○クローラー
1:クロールする
2:クロールしたものがキャッシュするに値するかを判定
⇒キャッシュしない場合終了
○インデクサー
1:キャッシュされたリストを順にみていってインデックスに値するかを判定
⇒インデックスしない場合終了
2:サイトを分析
3:(検索エンジンが独自に考えた理論で)インデックス
4:ついたインデックスに対してさらに独自の操作をしてポイントさらに操作
(ドメインエイジとかスパムみたいな文書解析とは別のレイヤーの作業)
5:検索結果を出すためのインデックス完成
このできたリストから検索結果を出すわけです
Yとかはこのインデクサーの作業が追いついていなくて、
定期的に 更新しました! といって全サイトのインデックス作業をやるわけです。
(Yahooの場合このインデクサーの作業4だけはこまめにやってる感じ)
が Googleはたぶん余裕で追いついているので、
随時やってるわけです。 だから随時変動。
—-
というのを踏まえて
・補足結果っていうのはたぶん インデクサーの作業の4でしてる作業の一つの集合
・Matt Cuttさんの言及 -> 4の作業をしない状態で5にいってしまった
・ヨーヨー現象 -> インデクサーの処理が早くなっただけじゃないのかな?
・ghost data-set -> こんなのあったらあのスピードで検索結果は出せないと思う。。
・site:とか -> Googleのインデックスは他のサイトからの影響を強く受けるわけだから
被リンク元のページにインデクサーが走った時、被リンク先のページの
評価が変わるのは自然だと思う。
というお話でした。
長ひ。。
結論
hyperestraierを使ってみよう(ぇ
11月 4, 2008
前回の続き
とりあえず強引に mysql4.0系でマルチバイト対応全文検索してみるだけ。
簡単に言えばトークンに切り出して、それをmd5して別テーブルに格納するという力ワザ。
どうやってトークンを切りだすか
以前流行った正規表現ベースのトークンとn-gramで速度比較
100文字ほどのデータだと
%php -f morph.php ←正規表現ベース
0.0232629776001sec
%
%php -f ngram.php ←tri-gram
0.029877967834sec
%
10万文字ほどのデータだと
%php -f morph.php ←正規表現ベース
8.76749396324sec%
%
%php -f ngram.php ←tri-gram
9.08151698112sec%
あんまりかわらないのでワンライナーな正規表現ベースでやってみる。
こんなかんじの正規表現。
$r = preg_match_all('/[一-龠々〆ヵヶ]+|[ぁ-ん]+|[ァ-ヴ]+|[a-zA-Z0-9]+|[a-zA-Z0-9]+/u', $str, $m);
この正規表現で各レコードの本文を割って
出てきたトークンを一つづつハッシュにしてjoinする
$tempToken = array();
foreach ($m as $v) {
$hashedToken[] = md5($v);
}
$joinedToken = join(' ',$hashedToken);
でこれをトークン専用カラムを作成してそこに突っ込む。
ここまでできたら
検索クエリも上の正規表現でトークンにしてそれをmd5にしてから検索。
テストしてみる
全文中から 86deb27a32903da70a7b2348fcf36bc3(あいうえおのmd5) を検索
SELECT id,MATCH (test_fulltext) AGAINST ('86deb27a32903da70a7b2348fcf36bc3')
FROM **table
WHERE MATCH (test_fulltext) AGAINST ('86deb27a32903da70a7b2348fcf36bc3')
ORDER BY MATCH (test_fulltext) AGAINST ('86deb27a32903da70a7b2348fcf36bc3') ASC
クエリの実行時間 0.0065 秒
おーあたったあたった。
しかもこれなら mysqld のft_min_word_lenを4からいじれないっていう件も
強制32文字になるわけだから解決!
ちょいと手間だし、トークンの数 * 32バイト分1レコードのデータが膨れ上がりますが
(まあ全文字md5にしないで、マルチバイトのとこだけ切り出してるわけだから、
そこだけエンコードしてしまえば結構減るかも)
こういう方法で一応できるということで。
っていうか pack() とか使えばもっと短くなるかな。
11月 4, 2008
とりあえずさくらのサーバに
全文検索も実装しようかなーと思ってsennaとか調べてたんですが、
色々と制約にヒットしてめんどくさくなったんで、
既存の範囲で全文検索ができないかと考えてメモ
ここらへんを参考に
MySQL 全文検索
MySQL FULLTEXT + Ngram : LIKE検索より数十倍高速な、お手軽 日本語全文検索 について
mysql の fulltext型のインデックスを使って実装するのが一般的らしい。
で このfulltext型ってのが何をやってるかといえば
MySQL では、非常に単純なパーサを使用してテキストをワード(語)に分割します。“ワード” とは、文字、数字、‘’’、‘_’ で構成される文字列です。
だそうで。
ただ、
MySQL 4.1.1 以降はマルチバイト文字も対応。
ただし Unicode は utf8 のみ対応 (ucs2はNG)。
えーっと さくらのDBは 4.0.27なわけですが・・・
さらに
4.1だと文字揺らぎの修正(半角<>全角とか)
+QUERY EXPANSION MODE という付加モードも使用可能。。
ということで、あきらかに4.1を使ったほうがいいんですが、
4.0でも最低限動かせないかなということで試行錯誤開始。
とりあえずやってみる
とりあえずそこらへんは無視して
既存にあるテーブル(レコード数6000)の
コンテンツテーブル(text型、1つのレコードにつきマルチバイトで1000文字くらい)のものでやってみる。
(DBはUTF-8統一)
ALTER TABLE **table ADD FULLTEXT(contents);
6000行もあるから結構かかるのかとおもったら5秒ほどで終了。
え これほんとにできてんのかな・・
とりあえずテスト
全文中から Screenshot っていう言葉を検索
SELECT id,MATCH (contents) AGAINST ('Screenshot')
FROM **table
WHERE MATCH (contents) AGAINST ('Screenshot')
ORDER BY MATCH (contents) AGAINST ('Screenshot') ASC
クエリの実行時間 0.0054 秒
おお早い早い。
ちゃんと結果も100件ほど出てきた。
LIKEにしてみる
SELECT *
FROM **table
WHERE contents LIKE '%Screenshot%'
クエリの実行時間 0.2419 秒
やっぱこっちは実用的じゃない。
しかも結果は160件ほど。
じゃあ日本語はどうかというと。。
全文中から ミュージック っていう言葉を検索
SELECT id,MATCH (contents) AGAINST ('ミュージック')
FROM **table
WHERE MATCH (contents) AGAINST ('ミュージック')
ORDER BY MATCH (contents) AGAINST ('ミュージック') ASC
クエリの実行時間 0.0057 秒
検索結果0。手動で入れてみたんだけどやっぱり0。
やっぱ機能していない。
でもまあ今更UTF8からEUCにDB変えるとかナンセンスすぎるので
どうしようかなーと。
やり方を考える
日本語トークンを切り出してハッシュにでもする?
できそうな気がしないでもないので、やってみる。
続き