ブラウザでもGroongaで検索したい阿部です。
Groongaがブラウザで動くようになったのでさっそく試してみた記事です。
この記事に関係する動画もあるので、動画もどうぞ。
はじめに
リポジトリの例のとおりにやれば使えます。 これは自分でビルドする例です。 このとき、一つだけ注意があってWASI SDKというのを事前にダウンロードして配置しておく必要があります。
この記事では例に従わず、すでにビルド済みのバイナリを使う方法で説明します。 とりあえず動かしてみたいときは、この方法のほうが簡単だからです。 ビルド済みのバイナリはGitHubのリリースページにあります。
次の流れで説明していきます。
- 環境など準備
- 必要なファイルの取得
- とりあえずブラウザで動かす
- Groongaのドキュメントを検索
1. 環境など準備
OSとかは何でも良いです。 Node.js v24以上があれば良いです。 今回はDockerを使います。
$ mkdir groonga-wasm # 適当なパスに作業用のディレクトリを作る
$ cd groonga-wasm
$ docker container run -it --rm node:26 --version
v26.11.1
注: Node.jsのバージョンが古いと動かない(coreを吐いて落ちる)ので新しいバージョンでお試しください。
2. 必要なファイルの取得
WASMを使うサンプルコードはリポジトリにあるので、リポジトリをcloneします。 加えてWASMのバイナリを取得します。
# 上からの続きで作業用のディレクトリ`groonga-wasm`にいる前提
sudo apt install -y git wget # gitとwgetがない場合はインストール(Debian、Ubuntuの例)
git clone --depth 1 https://github.com/groonga/groonga.git
wget https://github.com/groonga/groonga/releases/download/v16.1.3/groonga-wasm-16.1.3.tar.gz
tar -xzf groonga-wasm-16.1.3.tar.gz
この例ではGroongaのバージョン16.1.3を使っています。適宜変更してください。 試す時点の最新を使うとより良いです。
注: 16.1.2で追加されたのでそれ以降をご利用ください。
3. とりあえずブラウザで動かす
リポジトリの例を参考にブラウザで動かしてみます。
# 上からの続きで作業用のディレクトリ`groonga-wasm`にいる前提
# データベースを作る
mkdir groonga/examples/web/database
docker container run -it --rm \
-v ${PWD}/groonga-wasm-16.1.3:/wasm \
-v ${PWD}/groonga/examples/web:/web \
node:26 \
/wasm/bin/groonga.mjs -n /web/database/db 'table_create Memos TABLE_HASH_KEY ShortText'
# 確認用のWebサーバーを起動して確認
docker container run -it --rm \
-v ${PWD}/groonga-wasm-16.1.3:/wasm \
-v ${PWD}/groonga/examples/web:/web \
-p 127.0.0.1:8080:8080 \
node:26 \
node /web/serve.mjs --prefix /wasm
ブラウザで http://localhost:8080/ にアクセスすると確認できます。
スクリーンショット:

この画面でtable_listやselect Memos(データはないので0件のレスポンスですが)を実行すると動いているのが確認できます。
Webサーバーを起動していますが、Webサーバー側でGroongaが動いているわけではありません。 WebサーバーはデータベースファイルやWASMを含む静的なファイルを返しているだけです。 検索のもろもろはすべてブラウザ側で動いています。
注意
今のところ、WASMではない普通にビルドされたgroongaコマンドで作ったデータベースはWASMで開けません。
WASMで使いたい場合はgroonga.mjsコマンドなど、WASMで作ったデータベースをご利用ください。
ちょっと手を入れると読めるようになりそうなので、動くようになったら続報記事を書きます。
4. Groongaのドキュメントを検索
リポジトリの例ではデータがなくてさみしかったので、Groongaのドキュメントを登録したデータベースを作って試します。
データを登録するコード例です。
とりあえずのお試しということで、何も考えずHTMLをそのまま全部投入しています。
ExtractorHTMLを使ってテキスト部分のみを取り出してはいますが、サイドバーなどもコミコミのテキストを投入しています。
import { readdirSync, readFileSync } from "node:fs";
import { join, resolve } from "node:path";
import { pathToFileURL } from "node:url";
const [groongaWasmDir, htmlDir, dbPath] = process.argv.slice(2);
const { open, GRN_SUCCESS } = await import(
pathToFileURL(join(resolve(groongaWasmDir), "lib", "libgroonga-node.mjs"))
);
const groonga = await open();
const context = groonga.createContext();
context.createDatabase(resolve(dbPath));
const execute = (command) => {
context.sendText(command);
if (context.rc !== GRN_SUCCESS) {
throw new Error(`${command}: ${context.errorMessage}`);
}
};
try {
execute("table_create Pages TABLE_HASH_KEY ShortText");
execute("column_create Pages content COLUMN_SCALAR LongText");
execute("load --table Pages");
execute("[");
for (const path of readdirSync(htmlDir, { recursive: true })) {
if (!path.endsWith(".html")) {
continue;
}
const content = readFileSync(join(htmlDir, path), "utf8");
execute(JSON.stringify({ _key: path, content }) + ",");
}
execute("]");
execute("table_create Terms TABLE_PAT_KEY ShortText --default_tokenizer TokenNgram --extractors ExtractorHTML --normalizers 'NormalizerNFKC150'");
execute("column_create Terms pages_index COLUMN_INDEX|WITH_POSITION Pages content");
} finally {
groonga.close();
}
このコードを groonga/examples/web/create-doc-db.mjs に保存した場合の実行例です。
これまでと同様に作業用のディレクトリgroonga-wasmにいる前提です。
git clone --depth 1 https://github.com/groonga/groonga.org.git
rm -f groonga/examples/web/database/db* # 作ったデータベースを一旦削除
docker container run -it --rm \
-v ${PWD}/groonga-wasm-16.1.3:/wasm \
-v ${PWD}/groonga/examples/web:/web \
-v ${PWD}/groonga.org/ja/docs:/docs \
node:26 \
node /web/create-doc-db.mjs /wasm /docs /web/database/db
docker container run -it --rm \
-v ${PWD}/groonga-wasm-16.1.3:/wasm \
-v ${PWD}/groonga/examples/web:/web \
-p 127.0.0.1:8080:8080 \
node:26 \
node /web/serve.mjs --prefix /wasm
起動したブラウザで次のようなGroongaコマンドを実行すると、動いているのが確認できます。 (見やすいように改行を入れていますが、ブラウザの入力欄には1行で入力してください。)
select Pages \
--match_columns content \
--query 'インデックス 作成' \
--output_columns _key \
--sort_keys -_score \
--output_pretty yes
[
[
0,
1791774931.593,
0.003000020980834961
],
[
[
[
58
],
[
[
"_key",
"ShortText"
]
],
[
"reference/commands/column_create.html"
],
[
"news/5.html"
],
[
"tutorial/introduction.html"
],
[
"tutorial/match_columns.html"
],
[
"news/6.html"
],
[
"reference/commands/table_create.html"
],
[
"reference/commands/select.html"
],
[
"news/9.html"
],
[
"reference/indexing.html"
],
[
"news/7.html"
]
]
]
]
本文も表示すると長くなるので、_key(ドキュメントのパス)のみを表示していますが、ちゃんと検索できているのがわかります。
(Groongaユーザーであればパスだけ見ればわかるはず!)
実際はスニペットなどを表示すると良いでしょう。 (上述の通りサイドバーも含めてデータベースを作ったのでスニペットにもそこが表示されています。真面目にやる場合は本文のみを対象にすると良いでしょう。)
select Pages \
--match_columns content \
--query 'インデックス 作成' \
--output_columns '_key, snippet_html(html_untag(content))' \
--sort_keys -_score \
--limit 2 \
--output_pretty yes
[
[
0,
1791775240.843,
0.009999752044677734
],
[
[
[
58
],
[
[
"_key",
"ShortText"
],
[
"snippet_html",
null
]
],
[
"reference/commands/column_create.html",
[
".1. スカラーカラム\n7.6.2.2. ベクターカラム\n7.6.2.3. 擬似カラム\n7.6.3.1. <span class=\"keyword\">インデックス</span>カラム\n\n\n7.7. エクストラクター\n7.7.2.1. ExtractorHTML\n7.7.2.2. ExtractorJSON\n\n\n7",
" サジェスト\n7.21.1. はじめに\n7.21.2. 補完\n7.21.3. 補正\n7.21.4. 提案\n\n\n7.22. <span class=\"keyword\">インデックス</span>構築\n7.23. シャーディング\n7.24. 言語モデル\n7.25. ログ\n7.26. チューニン",
"いカラムを<span class=\"keyword\">作成</span>します。\n1つのレコードに複数の値を保存したい場合は1つ以上カラムを<span class=\"keyword\">作成</span>する必要があります。\nGroongaは<span class=\"keyword\">インデックス</span>をカラムとし"
]
],
[
"news/5.html",
[
"対する<span class=\"keyword\">インデックス</span>情報をすべて返すAPIを追加しました。\n[schema] <span class=\"keyword\">インデックス</span>を張っているテーブルとデータカラムに、該当<span class=\"keyword\">インデックス</span>の情報を",
"をサポートしている<span class=\"keyword\">インデックス</span>を使った検索を指定するために INDEX_COLUMN == VALUE と書けるようになりました。\n転置<span class=\"keyword\">インデックス</span>モジュールから出",
"ース - 2015-10-29#\n\n改良#\n\n[転置<span class=\"keyword\">インデックス</span>] 開発者向けのログのログレベルを下げました。\n新しいデータベースを<span class=\"keyword\">作成</span>したとき、変更をフラッシュす"
]
]
]
]
]
まとめ
Groongaがブラウザで動くようになったので試しました。 全文検索用のサーバーが不要でドキュメントの検索ができるので便利です。
Webページに組み込みたい、などの場合はクリアコードでサポートできますので、お問い合わせよりお気軽にお問い合わせください。
補足
WASM版ですがいろいろ制限があります。
例えばプラグインが使えないのでTokenMecabなどは使えません。
期待通りに動かなかった場合などはGitHubのissueやチャットからご質問ください。