いいね!数

0

閲覧数
389

Xpagesで、以下のことを実現させましたが、質問があります。

①会社名と会社の情報の入った文書の一覧がある(5000件ほど)

②①がSelCompanyW_Vビューに表示されている

③①とは別の文書で、会社名の一部を入れて検索ボタンをクリックするとダイアログで該当する会社名を

持つ文書が一覧で表示される。このときあいまい検索をする

上記のことを実現するため、③で表示されるダイアログの値に検索結果が表示されるよう

以下のコードをssjs1で書きました。

//関数
function countLength(str) { 
    var r = 0; 
    for (var i = 0; i < str.length; i++) { 
        var c = str.charCodeAt(i); 

        if ( (c >= 0x0 && c < 0x81) || (c == 0xf8f0) || (c >= 0xff61 && c < 0xffa0) || (c >= 0xf8f1 && c < 0xf8f4)) { 
            r += 1; 
        } else { 
            r += 2; 
        } 
    } 
    return r; 

//検索キーワードを変数にセット
    
    var key = @Trim(getComponent("CNameKey").getValue());
    if(key==""||key==null){
    return ;
    }
    if(key.indexOf("\"")!=-1){
    return;
    }
    key = key.replace(/[A-Za-z0-9]/g, function(s) {
        return String.fromCharCode(s.charCodeAt(0) + 0xFEE0);
    });    //全角
    key = key.toUpperCase();    //大文字
    
//検索結果(あいまい検索)を取得し、キーワード選択ダイアログを表示する
    var v:NotesView = database.getView("SelCompanyW_V");
    var vc:NotesViewEntryCollection = v.getAllEntries();
//キーワードの先頭1文字を全半角に変換し、変換できればキーワードの前に“*”(アスタリスク)を追加する
//対象は英数字のみ
    var key_left = key.left(1);
    var key_left8 = key_left.replace(/[A-Za-z0-9]/g, function(s) {
        return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
    });    //半角
        if(countLength(key_left)!=countLength(key_left8)){
     if (key_left.match(/[^A-Za-z0-9]+/)||key_left8.match(/[^A-Za-z0-9]+/)) {
     key ="*"+key
     }
    }
//キーワードの最後1文字を全半角に変換し、変換できればキーワードの後ろに“*”(アスタリスク)を追加する
//対象は英数字のみ
    var key_right = key.right(1);
    var key_right8 = key_right.replace(/[A-Za-z0-9]/g, function(s) {
        return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
    });    //半角

        if(countLength(key_right)!=countLength(key_right8)){
     if (key_right.match(/[^A-Za-z0-9]+/)||key_right8.match(/[^A-Za-z0-9]+/)) {
     key =key+"*"

     }
    }
    database.updateFTIndex(true);
    if(v.FTSearch( key, vc.getCount() )>0){
        vdoc = v.getFirstDocument();
        KeyList = [];
        key=key.replace( /\*/g , ".*" ) ;    
        while (vdoc != null){
            mStr =vdoc.getItemValueString("CompanyName");
            W_MAKRNM = mStr.replace(/[A-Za-z0-9]/g, function(s) {
            return String.fromCharCode(s.charCodeAt(0) + 0xFEE0);
            });    //全角
        
            W_MAKRNM= W_MAKRNM.toUpperCase();    //大文字
            var re = new RegExp(key);    
            if(W_MAKRNM.match(re)){
                    makr_str = vdoc.getItemValueString("CompanyName")+"◆"+vdoc.getItemValueString("CompanyNameKana")+
                    "("+vdoc.getItemValueString("CompanyAddress")+")";
                    KeyList.push(makr_str);
            }

            var vdoc = v.getNextDocument(vdoc);
        }
    }else{
        KeyList = ""
}
    
    
    v.clear()     //全文検索をクリア
    return KeyList
    

やっとの思いで書いたコードなのですが、反応が遅かったり、ボタンを押しても反応しなかったりします。

検索対象の文書が少ないと反応もよく、反応しないということはありませんでした。

このコードをもっと効率よく書く方法はありますでしょうか?

説明がうまくなくて申し訳ないです。説明の足りないところがありましたらご指摘ください。

よろしくお願い致します。

サーバー情報: | クライアント情報: | 
カテゴリ:アプリ開発 - XPages | タグ:
  | 質問日時:2017/05/19 11:17:09

回答・コメント

いいね!数

0

クリックするボタンのコードは以下の通りです。

(csjs)

var str = dojo.byId("#{id:CNameKey}").value;
if(str==null||str==""){
return ;
}
if(str.indexOf("\"")!=-1){
alert("検索文字に使用できない文字が含まれています。\n\n・半角ダブルクォーテーション");
return;
}
var dialog = dijit.byId("#{id:selectCategory1}");
dialog.show();

回答日時:2017/05/19 11:52:35

いいね!数

0

全部は見れていないですが、全文索引の更新 ( database.updateFTIndex()  ) を検索の度にやるのは

負荷がかかりそうだなと思いました。(もしかすると索引更新が終わるまで処理を待ってるかも?)


索引更新は定期的にやるとか別のタイミングでさせた方がよいかと思います。
「どうしても最新の索引の結果でないと困る!」という場合なら、文書作成または更新をトリガーにしたエージェントで更新させるとか・・・

回答日時:2017/05/19 15:16:32

いいね!数

1

最近は確認してないけど、XPages上でdatabase.updateFTIndex()実施しても索引は更新されなかったような。だもんで文書更新をトリガにしたLotusScriptの世界かなんかで更新かけないとだめだったような気がします。

あと、FTSeach()の検索クエリを工夫すれば検索キーの先頭と終端に"*"つけたり、全角半角の変換とかいらなかったような。時間がかかってるとしたら、やっぱりupdateFTIndex()ですかね。とりあえずupdateFTIndex()はずして速くなるか試してみるとか。

それでも遅いなら文字列の変換をやめてみる。

/Yac

回答日時:2017/05/21 12:16:30

いいね!数

0

ykawaさん、yac4423さん、

ご回答をありがとうございます。

まずはdatabase.updateFTIndex()を外してみたのですが、結果は変わりなく、動きが不安定でした。

次は文字列の変換等を外して確認してみたいと思います。

ちなみに検索対象の文書は5千件ぐらいです。3千件以内だと動作はなめらかだったのですが、3千件を超えたあたりから

動作が不安定になりました。

回答日時:2017/05/22 11:43:03

いいね!数

0

念のため確認ですが、データベースの全文検索用の索引は作成済みですか?

動作が不安定になるのは、検索対象の文書の数が増えた時か?それとも、検索にヒットする文書の数が多い時か?

索引さえ作ってあれば、登録されてる文書数が多少増えても、検索処理自体の重さはあまり違わない、という印象があります。

検索にヒットする文書がおおいと、ループする回数が増えるから、処理が重くなってきそう。Regexpのインスタンス、ループ内で毎回生成してるのとかちょっと気になります。

回答日時:2017/05/22 17:20:41

いいね!数

0

コードを読み解いてみると、検索対象は[CompanyName]フィールドだけなんですかね。  KeyList に入れるのは if(W_MAKRNM.match(re)) を満たすものだけに制限してるみたいだし。だったら、後述する感じのコードでいいんじゃないですかね。

動作確認まではしてないのでエラーになったらゴメンナサイ。ポイントは、

・検索クエリで[CompanyName]に検索キーワードが含まれているものだけを抽出。大文字/小文字は区別しないよう、索引を作る時のオプションで「大文字/小文字は区別する」のチェックは外しておく。

・これならv.FTSearch()の結果、vには目的の文書しか入ってないはずなので、それをKeyListに突っ込んでいく。

・while()ループの回数が多くなってもいいように、vdocはrecyle()しながらループさせる。

ただこの方法でも、マッチする文書数が数万件になるとKeyListに格納される文字列は結構大きくなってしまう。

私なら、マッチする文書のUNIDだけリストに突っ込んどいて、表示するときにUNIDを使って文書を開くかな。どうせ表示するときに一度に数万件ものデータが表示できるわけないのだから、<xp:repeat>のページャを使って、表示するときに実際に文書にアクセスして表示したい文字列を生成する。

/Yac

    	if(key==""||key==null){
          return ;
        }
        if(key.indexOf("\"")!=-1){
          return;
        }
        
        var v:NotesView = database.getView("list");
        // [CompanyName]を検索キーワードで検索
        var search_query = "[CompanyName] CONTAINS " + key;
        var count = v.FTSearch( search_query );
        var KeyList = [];
        if(v.FTSearch( search_query ) >0){
            var vdoc = v.getFirstDocument();
            while (vdoc != null){
                var makr_str = vdoc.getItemValueString("CompanyName")+"◆"+
                    vdoc.getItemValueString("CompanyNameKana")+
                    "("+vdoc.getItemValueString("CompanyAddress")+")";
                KeyList.push(makr_str);
                var next_doc = v.getNextDocument(vdoc);
                vdoc.recycle();  // 一応開放
                vdoc = next_doc;
            }
        }
        v.clear()     //全文検索をクリア
        return KeyList

 

回答日時:2017/05/22 22:35:16

いいね!数

0

yac4423さん、

丁寧な回答に感謝です。

頂いたコードでやってみたところ、少し速度がはやまりました。英数字の前方一致のあいまい検索ができなかったので

このコードに一部付け足して前方一致のあいまい検索もできるようにしました。

UNIDを使って文書を開く方法についても様子を見て検討したいと思います。

もうひとつ問題があるのですが、これはまた別のスレをたてたいと思います。

 

回答日時:2017/05/24 9:41:51