« sony braviaのストップモーション | メイン | お前は待機してたのか? »



mojaラボ気になるキーワード検索の解説

mojaラボ気になるキーワード検索の解説をはてなブックマークに追加 mojaラボ気になるキーワード検索の解説をdel.icio.usに追加  Yahoo!ブックマークに登録 mojaラボ気になるキーワード検索の解説をGoogle Bookmarksに追加 mojaラボ気になるキーワード検索の解説をtwitterにポスト
out.PNG

mojaラボ気になるキーワード検索について簡単に技術解説します。flickrぽいロゴは別に意味はありません。ココで作れますよ。
と言うわけで、たいしたことはやってないんですけど、いくつかのウェブapiを使っていますので、その紹介も含めて解説したいと思います。
すみません。今、firefoxだとちゃんと動かない模様です。えとinnerHTMLがfirefoxだとダメみたいですね。てことはこのページ下部のサイト内検索もうまく見れていないんですね。orz

<やりたかったこと>

・文章から特徴的な単語を抜き出して、主要な検索エンジンやウェブサービスの結果を返す。
→ここでいう文章は、主にブログエントリなんかを期待してます。
※ちなみに入力されたエントリをログにとったりはしてません。

<実現できていないこと>

・tf-idfという、まさに文章の特徴的な単語の抽出が出来ていません。
→代わりにkizAPIの、きざしランキングウェブサービスを利用しました。

それでは、どういう仕組みになっているのがを簡単に説明します。

  1. "きざしランキングウェブサービス"から、今日話題になったキーワードとその間連語300語くらいを取得する
  2. yahoo developer networkの"形態素解析ウェブサービス"を使って入力した文章を解析する。
  3. 解析結果の単語が1.のランキングに載っていれば、出力したタグクラウドのフォントカラーをいじる。
  4. 出力したタグクラウドのワードをオンクリックで"google search ajax api"による検索とkizAPIの"KWIC(KeyWord In Context)検索"を行う。

<ajaxとクロスドメインの問題>

まず、各々のウェブサービスの呼び出しについてです。
ajaxで使うXMLHttpRequestというインスタンスは、今そのページが表示されているドメインから、それ以外のドメインに対してリクエストを送ることが出来ませんので、(IEだと「書き込みできません」というスクリプトエラーになります)自分のドメインでプロキシっぽい動きをするサービスを用意してみました。
つまり、

javascript 自分のプロキシウェブサービス yahoo とか kizAPI ウェブサービス
javascript 自分のプロキシウェブサービス

のようにして呼び出して戻りのxmlを得ている訳です。

このやり取りを抜粋すると、こういうことになります。

・プロキシ側

    # $sendURLはkizAPIなどのウェブサービス呼び出し先。$_GETなどを判定して適宜変更する。
    $req =& new HTTP_Request( $sendURL );
    $req->setMethod( HTTP_REQUEST_METHOD_GET );
    if ( !PEAR::isError( $req->sendRequest() ) ) {
        # ヘッダーをContent-Type: text/xmlで返してあげないとスクリプトが理解してくれない
        header('Content-Type: text/xml');
        echo $req->getResponseBody();
    }

・呼び出し側

    // crtXmlHttpReqはファクトリみたいなもの。XMLHttpRequestインスタンスを返します。
    httpInst = crtXmlHttpReq( getWordRankData );
    if ( httpInst ){
        httpInst.open( "GET", "proxy.php?qry=1", false );
        httpInst.send( "" );
    }

・XMLを取得する

function getWordRankData()
{
    if ( ( httpInst.readyState == 4 ) && ( httpInst.status == 200 ) ){
        var xmlData = httpInst.responseXML;

スクリプトがproxy.phpにパラメータを渡して、proxy.phpがそのパラメータによって呼び出し先を適宜変更してあげる感じです。
ちなみにこういうプロキシサービスを作らなくてもJSONP(JSON with padding)という方法をとれば、プロキシなくても出来るようです。ふへー。throw lifeさんに判りやすい説明がありました。

<Prototype.jsの利用>

きざしランキングウェブサービスで返ってくるxmlのCDataのリンクタグを削除したいのでstripTags()を使いました。つまりローカルでデータを整形しています。コレはサーバでやらんとだめですね。。。
via:http://www.prototypejs.org/

<形態素解析>

文章に上限がないとなかなか結果が返ってこないので、送信できる文章は2048文字以内の制限を掛けています。 yahooの形態素解析は1度に送れるバイト数の上限を定めていますので、ブラウザからもらったテキストは適宜分割して形態素解析を行っているわけです。
※本当は解析を行った結果をさらに、tf-idfで重要語句を判定したかった。

・wordanalysis.phpの抜粋

    # $curMsgListは入力した文章を適当なデリミタでarrayにしています。
    # -----------------------------------------------------------------------------
    # センテンス毎に形態素解析
    # -----------------------------------------------------------------------------
    require_once( 'HTTP/Request.php' );
    $req =& new HTTP_Request( "http://api.jlp.yahoo.co.jp/MAService/V1/parse" );
    $arySize = count( $curMsgList );
    for( $idx = 0; $idx < $arySize; $idx++ ){
        $req->setMethod( HTTP_REQUEST_METHOD_POST );
        $req->addPostData( "appid", "**********" );
        $req->addPostData( "results", "uniq" );
        $req->addPostData( "response", "surface" );
        $req->addPostData( "filter", "1|2|9" );
        $req->addPostData( "sentence", $curMsgList[ $idx ] );

        if ( !PEAR::isError( $req->sendRequest() ) ) {
            $res = $req->getResponseBody();
            $xml_parser = new xml();
            $xml_parser->parse( $res );
            # ループ中のxmlパーサなのでunsetしておく。
            unset( $xml_parser );
        }
        $req->setURL( "http://api.jlp.yahoo.co.jp/MAService/V1/parse" );
        $req->clearPostData();
    }

<XMLパーサ>

xmlパーサは以下のようなクラスを作ってパースしています。"SURFACE"タグに目的のワードが入っているわけですね。
ちなみにこのクラスのインスタンスはパースが終了するごとに、unset( $xml_parser );のように開放しないとうまく動きませんでした。1つのインスタンスで複数のxmlをパース出来ないんでしょうね。多分。
尚、$retAryは返却するxmlの実データになるのですが、C++のSTLで言うpairのfirstに解析後の単語、secondにその嵩みが入っています。

・wordanalysis.phpの抜粋(xmlパーサクラス)

    class xml {
        var $parser;
        function xml(){
            $this->parser = xml_parser_create( 'UTF-8' );
            xml_set_object( $this->parser, $this );
            xml_set_element_handler( $this->parser, "TagOpen", "TagClose" );
            xml_set_character_data_handler( $this->parser, "CData" );
        }
        
        function parse( $data ){
            xml_parse( $this->parser, $data );
        }

        function TagOpen( $parser, $tag, $attributes ){
            global $refPrs;
            if( $tag == "SURFACE" ){
                $refPrs = $tag;
            }
        }

        function CData( $parser, $cdata ){
            global $refPrs;
            global $retAry;
            if( $refPrs == "SURFACE" ){
                if( isset( $retAry[ $cdata ] ) ){
                    $retAry[ $cdata ] += 1;
                }
                else {
                    $retAry[ $cdata ] = 1;
                }
            }
        }

        function TagClose( $parser, $tag ){
            global $refPrs;
            $refPrs = "";
        }
    }

<タグクラウドの生成>

後は、スクリプトのgetWordRankDataメソッドで取得したワードランク(refAryに格納されています)と解析後のワードをつき合わせてタグクラウドを生成しています。
wordanalysis.phpが返すXMLはcountタグにワードの嵩みが入っていて、コレがフォントサイズになります。itemタグには実際のワードが入っています。

function getElement()
{
    if ( ( txHttpInst.readyState == 4 ) && ( txHttpInst.status == 200 ) ){
        var xmlData = txHttpInst.responseXML;
        var elemListTags = xmlData.getElementsByTagName( "elem" );
        var countListTags = xmlData.getElementsByTagName( "count" );
        var itemListTags = xmlData.getElementsByTagName( "item" );
        var elemSize = elemListTags.length;

        resultText = "";
        for( i = 0; i < elemSize; i++ ){
            var wordCnt  = countListTags[i].childNodes[0].nodeValue;
            var itemName = itemListTags[i].childNodes[0].nodeValue;
            var color = "";
            
            // refAryの中身は↓な感じで格納されています
            // "オカザイル イケ EXILE 最高 岡村 岡村さん 見た 岡村隆史 面白かった のめちゃ ダンス" ... 
            // indexOfでヒットすればフォントカラーをいじります。
            for( ref = 0; ref < refAry.length; ref++ ){
                if( refAry[ ref ].indexOf( itemName ) > 0 ){
                    color = "style=\"color:#f93\"";
                    break;
                }
            }
            resultText = resultText + " <a href=\"#\" onclick=\"getReferWord( '" + itemName +  "' );OnLoad( '" + itemName + "' );\"><font size=\"" + ( wordCnt * 2 ) + "\" " + color + ">" + itemName + "</font></a> ";
        }
        $("result").innerHTML = resultText + "<ul><li>よく使われるキーワードを大きく表示しています</li><li>話題のキーワードをオレンジ色に表示しています。</li></ul><hr size=0 noshade />";
    }
    else {
        $("result").innerHTML = "解析中です。。。";
    }
}

タグクラウドのリンクタグにonclickでスクリプトを埋め込んでいます。これで、クリック時に検索キーワードを渡してgoogle検索と兆し検索が行われるという動きになります。
ここら辺は如何様にでもアレンジが出来そうですね。
via: throw life kizAPI yahoo developer network google search ajax api prototypejs

★このコンテンツに目的の情報はありませんでしたか?


[ 最近のエントリーとその関連エントリー ]


[ スポンサードリンク ]

トラックバック

このエントリーのトラックバックURL:
http://mojalog.com/cgi/mt/mt-tb.cgi/137

コメントを投稿

ツリータイプ・カテゴリー

open all | close all

リファラから検索


サイト内検索