検索機能を仮実装してみた。問題が山ほどあるとわかった。

ブツ

search.png

インストール&実行

NAME='Electron.MyLog.20220925111745'
git clone https://github.com/ytyaru/$NAME
cd $NAME
npm install
npm start

情報源

やったこと

検索機能を仮実装してみた。Electronアプリ側で検索ボックスに入力したキーワードを含むつぶやきを全件表示する。

SQL

DBはSQLite3を使用している。検索は以下SQL文を発行することで行う。キーワードで部分一致したものが対象。

select * from comments where content like '%${keyword}%';

これに最新順になるようソートをかける。

select * from comments where content like '%${keyword}%' order by created desc;

IPC通信

ElectronのIPC通信用インタフェースとして実装する。

main.js

ipcMain.handle('search', async(event, keyword) => {
    const res = lib.get(`DB`).exec(`select * from comments where content like '%${keyword}%' order by created desc;`)
    console.log(res)
    return (0 === res.length) ? null : res[0].values
})

preload.js

search:async(keyword)=>await ipcRenderer.invoke('search', keyword),

呼び出す

index.html

検索用テキストボックスを用意する。

<input id="search" type="search" placeholder="検索">

renderer.js

検索用メソッドを呼び出す。

const records = await window.myApi.search(e.target.value)

inputイベントで実行する。

イベント 意味
input 1字入力するたび
change Enterキーで決定するたび

実際には色々ルート分岐する必要があった。

条件 結果
キーワードがない 最新20件表示する
検索結果がない 何も表示しない
ほか 検索されたつぶやきを全件表示する
document.querySelector('#search').addEventListener('input', async(e)=>{
    if (0 < e.target.value.length) {
        console.log('検索キーワード:', e.target.value)
        const records = await window.myApi.search(e.target.value)
        console.log(records)
        if (records) {
            document.getElementById('post-list').innerHTML = records.map(r=>TextToHtml.toHtml(r[0], r[1], r[2], document.getElementById('address').value)).join('')
        } else { document.getElementById('post-list').innerHTML = '' }
    } else {
        const records = await window.myApi.getPage(20, 0)
        document.getElementById('post-list').innerHTML = records.map(r=>TextToHtml.toHtml(r[0], r[1], r[2], document.getElementById('address').value)).join('')
    }
})

今回はまだAutoPagerは実装できなかった。それ以前に後述するバグがある。

バグ

AutoPagerとの兼ね合いでバグる。

スクロールを最下端にやると全件取得の最新から20件を取得してしまう(検索キーワードと関係なく)。下の図でいうと右下にあるの下に20が出てしまっている所がそれ。検索キーワードはなのにが入っていない20が出ている。これは全件取得の最新21件目のデータであり、検索結果ではない。

bugautopager.png

今はそういう実装なので、このへんを全面的に変えないとダメ。大変そう。

課題

  • 大文字と小文字を区別したい(LIKE句では区別しない仕様)
  • メタ文字をエスケープしたい(%, _がメタ文字。like '%10$%' escape '$'
  • 取得件数を表示したい
  • ページングを実装したい(最新順20件ずつ)
    • LIMIT句、OFFSET
  • LIKE句による検索は遅い
  • AND, OR検索したい
    • キーワードをスペース区切りにしたら各語ごとにANDをかけたい(現状はスペースもキーワードの一部になってしまう)
    • 表記ゆれに該当するものをOR検索したい
  • 一致率に応じて優先順位を算出したい

たかが検索だが、実装しようとすると大変。やりたいことが山のようにある。でもこれをすべて実装するのは無謀。

そこで最も簡単と思われるLIKE句による検索のみ仮実装してみた。それでも問題が残ってる。