php5の質問です。

現在文字列の比較部分を高速化するために悩んでいます。

対象文字列、キーワード(2~40byte程度で300語句以上)ともに日本語,大文字,小文字,記号など
対象文字列の文中にキーワードがマッチングするかどうかを判定。
foreach ($keywords_array as $key => $value) {
if (stripos($title, $key)!==False) {
matching($value);
break;
}
}
対象文字列に規則性が無いので、正規表現は使えないかな?と思い
上記のようなコーディングになりましたが、何かよりよい高速化への手法があればご教授ください。

※サーバはレンタルサーバなので高速化ツールは考えておりません。

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2008/12/22 13:15:49
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:munyaX No.1

回答回数120ベストアンサー獲得回数24

ポイント300pt

何度も同じデータに対して検索をかけるような案件であれば、データベースのようにあらかじめ

インデックスを作成しておき、部分一致ではなく、完全一致させることで高速化を狙うという

手法があります。

■コード例

//データ用意

$arr = array(

'親譲(おやゆず)りの無鉄砲(むてっぽう)で小供の時から損ばかりしている。'

, '小学校に居る時分学校の二階から飛び降りて一週間ほど腰(こし)を抜(ぬ)かした事がある。'

, 'なぜそんな無闇(むやみ)をしたと聞く人があるかも知れぬ。別段深い理由でもない。'

);

//インデックス

$idx = array(

'おやゆず' => 0

, 'むてっぽう' => 0

, 'こし' => 1

, 'ぬ' => 1

, 'むやみ' => 2

);

//---------

//処理1

//---------

$start = nowtime();

$key = 'むやみ';

for($i=0; $i<100000; $i++ )

foreach($arr as $tmp)

if(stripos($tmp, $key) !== False )

break;

echo nowtime() - $start . "\n";

//---------

//処理2

//---------

$start = nowtime();

$key = 'むやみ';

for($i=0; $i<100000; $i++ )

foreach($arr as $tmp)

if( array_key_exists($key, $idx) )

break;

echo nowtime() - $start . "\n";


//http://rikimaru-0720116.cocolog-nifty.com/blog/2008/10/php-b0c1....

function nowtime(){

list($usec, $sec) = explode(" ", microtime());

return ((float)$usec + (float)$sec);

}

?>

■実行結果

$php a.php

2.67902994156

0.140805959702


単語の切り出しは、形態素解析などを用いればOKかと。

レンサバの場合、入っていないことが多いと思いますので、あらかじめローカルで作成するか

Yahoo!のWebAPIを利用するなんて方法もあります。

http://developer.yahoo.co.jp/webapi/jlp/ma/v1/parse.html

http://mecab.sourceforge.net/

もしインデックスを用いると検索性が落ちるようであれば、最初はインデックスを見に行き

そのあと全件走査するだけでも違ってきます。

 ※もちろん使われ方によりますが。

id:iketerummo

・インデックスの利用

・ベンチマークの手法

・単語切り出しAPI

非常にためになりました。

そして完全一致は盲点でした、対象文字に造語が多く切り出しが難しいですが

比較計測し、高速化できるパターンを組み込みたいと思います。ありがとうございます。

引き続き募集します。

2008/12/16 13:53:29
  • id:munyaX
    すみません、処理2がイミフになってましたorz
    foreachする必要がないので本来は以下のような感じです。

    //---------
    //処理2
    //---------
    $start = nowtime();
    $key = 'むやみ';
    for($i=0; $i<100000; $i++ )
    if( array_key_exists($key, $idx) )
    ;

    echo nowtime() - $start . "\n";


    ちなみに、ベンチマークはPEARのBenchmarkを使うのが慣例となっているようなので、
    お仕事などの場合はこちらに慣れておかれるとよいかと思います。
    http://paranoid.dip.jp/kaworu/2007-03-10-1.html
    #今回はコピペで簡単に動いた方がよいだろうと思って使いませんでした。



    主題と外れますが、もしMySQLが利用できるなら、以下の手法を使うのも手です。
    http://www.tatamilab.jp/rnd/archives/000390.html
    http://www.tatamilab.jp/rnd/archives/000389.html
     ※導入する際、日本語環境だと若干クセがありますが。

    ちょっぱやです。
    ご参考までにー。
  • id:iketerummo
    処理2は何とか理解できていました。ご親切にありがとうございます。

    またMySQLの手法も助かります。
    とくにゆらぎ(utf8)はキーワード数を絞れるため結果速度アップになります。
    v4.1.1に少し足りないのでマルチバイト対応はできませんが、将来のために
    ロジックだけは考慮しておこうと思います。
    質問終了の際にはポイント上乗せさせていただきます!

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません