ククログ

株式会社クリアコード > ククログ > 2026 > Groongaがブラウザで動くようになったよ!

Groongaがブラウザで動くようになったよ!

ブラウザでもGroongaで検索したい阿部です。

Groongaがブラウザで動くようになったのでさっそく試してみた記事です。

この記事に関係する動画もあるので、動画もどうぞ。

はじめに

リポジトリの例のとおりにやれば使えます。 これは自分でビルドする例です。 このとき、一つだけ注意があってWASI SDKというのを事前にダウンロードして配置しておく必要があります。

この記事では例に従わず、すでにビルド済みのバイナリを使う方法で説明します。 とりあえず動かしてみたいときは、この方法のほうが簡単だからです。 ビルド済みのバイナリはGitHubのリリースページにあります。

次の流れで説明していきます。

  1. 環境など準備
  2. 必要なファイルの取得
  3. とりあえずブラウザで動かす
  4. 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やチャットからご質問ください。