« 検索パネルのリニューアル | トップページ | 文書履歴の自動調節 »

2013年2月18日 (月)

検索リニューアルの技術的背景

検索の高速化

以前のコードで「乾癬」を全文検索してみたところ,PatientModel で 217件のヒットがあり,結果の表示までに15秒程度かかってしまった。どこで時間をとっているか調べてみたところ,最終受診日と健康保険情報の取得のところで大量のクエリが発生しており,ここで 14.2秒を消費していた。
 そこで,最終受診日を取得するクエリを 1回ですますように工夫し,さらに健康保険情報をあらかじめ取得せず,カルテをオープンする時に初めて取りに行くようにしたところ,15秒かかっていた検索時間を 1秒以下に減らすことができた。
 試しにリニューアルしたコードで「紅斑」を検索してみたところ,7,377件のヒットがあり,さすがにここまで多いと表示までに 30秒かかってしまった。件数があまり多い場合には,100件ずつ分けて表示する等の対処方法が考えられるが,今のところ,こんな検索をする方が悪いということにしておく。

RemotePatientServiceImpl.java

// pvt をまとめて取得する(高速化のため)
List<PatientVisitModel> pvts = em.createQuery("from PatientVisitModel p "
    + "where p.facilityId = :fid and p.status != :status and (p.patient in (:pts)) order by p.pvtDate desc")
    .setParameter("fid", fid)
    .setParameter("pts", ret)
    .setParameter("status", KarteState.CANCEL_PVT)
    .getResultList();

// まとめて取った pvt から最新の日付を PatientModel にセット
for (PatientModel pm : ret) {
  for (PatientVisitModel pvt : pvts) {
    // 最初にマッチした pvt が最新 (last visit) 
    if (pm.getId() == pvt.getPatient().getId()) {
      pm.setLastVisit(pvt.getPvtDate());
      break;
    }
  }
}

AbstractMainComponent

public void openKarte(final PatientModel patient) {
  if (canOpen(patient)) {
    Thread t = new Thread() {
      @Override
      public void run() {

        // 健康保険情報をフェッチする
        PatientDelegater pdl = new PatientDelegater();
        pdl.fetchHealthInsurance(patient);
    :

 

絞り込み検索

Hibernate search で,AND/OR 検索が普通にできるのは Apache Lucene Query Parser というのが検索語を解釈してクエリに変換してくれているからであった。つまり,PatientModel をインデックスしてあれば,検索語のレベルで PatientModel の id で絞り込み検索ができるようになる。
 そこで,下のようにインデックスを追加した。なお,DocumentModel は KarteEntryBean を extend してあり,DocumentModel が @Indexed されているので,KarteEntryBean も @Indexed 状態になっている。

KarteEntryBean.java
   @IndexedEmbedded
   KarteBean karte
 
KarteBean.java
    @IndexedEmbedded
    PatientModel patient

インデックスをつけると,@Field がついていなくても @Id は自動的に検索対象になる。つまり,上記のインデックス付けをすると,KarteBean と PatientModel の id が自動的に検索対象になり,それぞれ "karte.id","karte.patient.id" というキーで検索できる。例えば PatientModel の primary key = 945 で絞り込みをしたい場合,"SearchText AND karte.patient.id:945" という検索語で検索できるようになる。今回作成した全文検索の絞り込み検索モードにこれを利用している。

 

入力フィールドの補完

Java Swing Hacks を参考に,入力履歴を覚えておいて補完する CompletableJTextField.java を作った。いろいろ Listener をつけて,入力中に矢印キーで履歴を選択できるようにしたり,リターンキーで自動的に補完履歴に登録されるようにしたり,補完ウインドウが出ているときにフォーカスを失った場合や,フレームを動かした場合の処理なども加えている。なお,補完ウインドウを半透明にするコード(com.sun.awt.AWTUtilities.setWindowOpacity)は java 7 では動かないらしい。

« 検索パネルのリニューアル | トップページ | 文書履歴の自動調節 »

OpenDolphin」カテゴリの記事