Seo tools

Neo Inspiration

  • Search

    • About Me

      • inspi 改め
        jakk@webアーキテクト(自称)
        php,javascript,seoなど
        得意技は extract();



  • Categories

  • Ranking

  • Comments

  • Others


  • mysql4.0系でfulltextを利用したマルチバイト全文検索1

    11 月 4th, 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変えるとかナンセンスすぎるので
    どうしようかなーと。

    やり方を考える

    日本語トークンを切り出してハッシュにでもする?

    できそうな気がしないでもないので、やってみる。

    続き


    phpでマルチスレッド

    10 月 29th, 2008

    またまた自作フレームワーク用に組み込みたかった機能の話

    特にfile_get_contentsなどの相手側の応答いかんで処理時間がかわるような場合
    同時にだーって流しておきたいなーとはおもったんですが、
    考えていたやりかたはモジュール版だと使えないということが発覚・・
    (pcntl_forkって関数)

    で今回みっけたのは curl_multi
    PHP curl_multi example of parallel GET requests

    注意点としては、各ハンドラが独自にキャッシュしてるから
    ハンドルを変更せず再度 curl_multi_exec しても
    トライせずにキャッシュを返すことかなぁ
    (その場合一旦ハンドラを解除して再セットすればOKらしい)

    なので、こんな感じでクラスを作って
    localhostのphpファイルを呼び出せば
    簡単にマルチスレッドでプログラムが動かせると。

    まあよっぽどのことがないと使わないとおもいますが。

    というかこれ、どこまでいけるんだろう。

    Class Parallel {
    
        public $result;
    
        public function __construct() {
        }
    
        public function execute($urlList = array()) {
            if (count($urlList) > 0) {
                $channel = array();
                $uniqueUrls = array();
                $uniqueUrls = array_unique($urlList);
    
                //マルチプロセスハンドラ
                $multiHandle = curl_multi_init();
    
                //URLに一つづつチャンネルを割り当てる
                foreach ($uniqueUrls as $k=>$v) {
                    $channel[$k] = curl_init($v);
                    curl_setopt($channel[$k], CURLOPT_RETURNTRANSFER, 1);
                    curl_multi_add_handle($multiHandle,$channel[$k]);
                }
    
                while (CURLM_CALL_MULTI_PERFORM == ($execReturn = curl_multi_exec($multiHandle,$isActive))) {
                }
    
                while ($isActive && $execReturn == CURLM_OK) {
                    if (curl_multi_select($multiHandle) != -1) {
                        while (CURLM_CALL_MULTI_PERFORM == ($execReturn = curl_multi_exec($multiHandle,$isActive))) {
                        }
                    }
                }
    
                if ($execReturn != CURLM_OK) {
                    return false;
                }
    
                $resultData = array();
                foreach ($uniqueUrls as $k=>$v) {
                    $curlError = curl_error($channel[$k]);
                    if ($curlError == “”) {
                        $resultData[$k] = curl_multi_getcontent($channel[$k]);
                    } else {
                        $resultData[$k] = ‘error’;
                    }
                    curl_multi_remove_handle($multiHandle,$channel[$k]);
                    curl_close($channel[$k]);
                }
    
                curl_multi_close($multiHandle);
    
                $this->result = $resultData;
                return true;
            } else {
                return false;
            }
        }
    
    }
    

    XML DB

    10 月 28th, 2008

    10万くらいのRSSをうまく管理するのはどうすっかなーと
    新しいシステムについてつらつら考えていたのだけれど、
    ふとXMLベースのDBってどうなんだろうと思い出して調査開始。

    キャッシュがきかない、トランザクションがきかない
    とかI/O周りの負荷が高すぎて
    結局具合のいいパーサかいてやるか
    一旦mysqlに格納しちまったほうがよさそうだなー

    と思いつつとりあえず使ってみた。

    Xprioriってのでテスト
    Xpriori

    ここらへんを参考にXquery(SQLの代わりに投げるDB用クエリ)をいじってみる
    Xquery

    ・・・
    スキーマレスDBっていうのは
    RSSのようにスキーマがガンガン変わるようなものを
    一括で管理するにはいいとおもったんだけど、
    どうも勝手がちがったw

    JOINとかは1ファイル1テーブルで、JOINはファイルを結合してくイメージだから・・
    あかんw10万ファイルをJOIN(実質MAX1000くらいなんだろうけど)
    とか気が遠くなるこれw

    10万ファイルをDBに格納してRSSを生成しなおすのと(こっちは格納コストが高い)
    ファイルとして保持して、Xqueryで生成するのと・・(こっちは生成コストが高い)
    うーん ちょっと簡単にはコスト計算できそうもないので、要検証。
    パーサ書くほうが楽しいしとりあえずやめよっかなーとか。

    余談だけどXqueryに関するこの記事をよんで
    めっちゃ面白そうだとはおもった
    http://d.hatena.ne.jp/stemy/20060708/1152385620


    2008/11/22 09:15:20