0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Google ColabでApache Luceneの日本語検索を試す — nlp4j-local-search 0.6.1

0
Posted at

Google ColabでApache Luceneの日本語検索を試す — nlp4j-local-search 0.6.1

はじめに

全文検索を試したいとき、Elasticsearch、OpenSearch、Apache Solrなどを用意する方法があります。

これらは非常に強力ですが、

まずは日本語の文書を数万件くらいLuceneで検索してみたい

という実験では、もう少し手軽な方法があってもよいと思います。

そこで開発しているのが nlp4j-local-search です。

nlp4j-local-search は、Pythonから Apache Lucene をローカルに利用するためのライブラリです。

検索サーバーやDockerを起動しなくても、Pythonプロセスの中からLuceneの全文検索機能を利用できます。

また、日本語検索にも対応しています。

Version 0.6.1 では、

nlp4j-local-search

という対話型CLIを利用できるようになりました。

今回は Google Colab を使って、

  1. nlp4j-local-searchをインストール
  2. Wikipediaの日本語サンプルデータをダウンロード
  3. CLIを起動
  4. 日本語全文検索
  5. フレーズ検索
  6. フィールド検索
  7. AND検索
  8. 日付範囲検索
  9. view() によるカテゴリ集計

までを、セルを上から順番に実行しながら試してみます。

ローカルPCへの環境構築は必要ありません。


1. Google Colabを開く

まずGoogle Colabで新しいNotebookを作成します。

今回は特別なGPUは必要ありません。

通常のCPUランタイムで試すことができます。


2. nlp4j-local-search 0.6.1をインストールする

最初のセルで次を実行します。

!pip install -q nlp4j-local-search==0.6.1

インストールできたことを確認します。

!nlp4j-local-search --help

nlp4j-local-search のヘルプが表示されれば準備完了です。

PyPI:

https://pypi.org/project/nlp4j-local-search/0.6.1/

3. Javaも確認してみる

nlp4j-local-search の内部ではJavaとApache Luceneを利用しています。

Google Colabには通常Java実行環境が用意されているので、確認してみます。

!java -version

このように、

openjdk version ...

と表示されればOKです。

利用者がJavaコードを書く必要はありません。

内部構造のイメージは、

Google Colab
    ↓
Python
    ↓
nlp4j-local-search
    ↓
Java
    ↓
Apache Lucene

です。


4. 日本語Wikipediaのサンプルデータをダウンロードする

今回のために、日本語Wikipediaのdumpから作成した漫画関連の記事データを用意しました。

次のセルを実行します。

!wget -q \
  https://nlp4j-2.sakura.ne.jp/data/wiki/jawiki-20260801-pages-articles_compact_manga.jsonl.gz \
  -O /content/jawiki_manga.jsonl.gz

ファイルを確認します。

!ls -lh /content/jawiki_manga.jsonl.gz

このデータはgzip圧縮されたJSONLです。

nlp4j-local-search.jsonl.gz を直接読み込めるため、展開する必要はありません。


5. 中身を少し見てみる

JSONLの中身をPythonから少し確認してみます。

import gzip

with gzip.open(
    "/content/jawiki_manga.jsonl.gz",
    "rt",
    encoding="utf-8",
) as f:
    for _ in range(3):
        print(f.readline())

1行が1文書になっています。

例えば、データには次のようなフィールドがあります。

id
title_s
text_ja
timestamp_dt
category_s

フィールド名の末尾にも意味があります。

例えば、

text_ja

は日本語全文検索用のテキスト、

category_s

は文字列のKeywordフィールド、

timestamp_dt

は日付フィールドです。


6. Colabから対話型CLIを起動する

通常のターミナルなら、

nlp4j-local-search --lang ja

と実行して、

>>

というプロンプトに直接入力できます。

Google Colabでは、セルをまたいでCLIプロセスを保持するために pexpect を使うと便利です。

次のセルを実行します。

import pexpect

cli = pexpect.spawn(
    "nlp4j-local-search --lang ja",
    encoding="utf-8",
    timeout=120,
)

cli.expect(">> ")
print(cli.before)

次のように表示されます。

nlp4j-local-search
Language: ja
Auto analyze: False
Type 'help' or '?' for help.

これで、バックグラウンドに nlp4j-local-search のCLIプロセスが起動した状態になります。


7. Colab用の小さなヘルパーを作る

CLIにコマンドを送信し、次のプロンプトまでの結果を表示する関数を作ります。

def run_cli(command, timeout=120):
    print(f">> {command}")
    cli.sendline(command)
    cli.expect(">> ", timeout=timeout)
    print(cli.before)

これ以降は、

run_cli('search("京都")')

のようにしてCLIを1コマンドずつ試せます。

Notebookなので、気になるところでセルを止めたり、検索語を変えて何度でも再実行できます。

これがColabで試す大きなメリットです。


8. CLIのhelpを見る

まずhelpを表示してみます。

run_cli("help")

CLIには、

load(...)
fields
aggregatable_fields
count
search(...)
view(...)
exit

などのコマンドがあります。

見た目をPythonの関数呼び出しに近づけています。


9. Wikipediaデータをロードする

それでは、先ほどダウンロードしたデータをロードします。

run_cli(
    'load("/content/jawiki_manga.jsonl.gz")',
    timeout=300,
)

処理が完了すると、例えば次のように表示されます。

Loaded 30,956 documents in ... seconds (... docs/sec).

実行時間は環境によって変わります。

この時点で、約3万件の日本語Wikipedia文書がApache Luceneのインデックスに登録され、検索可能になっています。


10. 文書数を確認する

run_cli("count")

今回のデータでは、

30,956

程度の文書が入っています。

ここから検索を試していきます。


11. まず普通に日本語検索してみる

例えば「高橋留美子」を検索してみます。

run_cli('search("高橋留美子", 5)')

検索結果には、

[id] score=...
本文...

という形式で、Luceneのscoreと文書が表示されます。

ここで行っているのは単純な、

"高橋留美子" in text

のような文字列検索ではありません。

--lang ja を指定しているため、日本語Analyzerを利用したLuceneの全文検索になります。


12. 自分で検索語を変えてみる

Colabではセルをコピーして、検索語だけ変えることができます。

例えば、

run_cli('search("漫画家", 5)')

あるいは、

run_cli('search("少年漫画", 5)')

などを試してみます。

Notebookでは、

ちょっと違う単語でも検索してみよう

という実験をすぐ行えるのが便利です。


13. フィールド一覧を見る

次に、Luceneインデックスにどのようなフィールドが登録されたのか確認します。

run_cli("fields")

例えば、

id
body
text
text_en
text_ja
category_s
title_s
timestamp_dt
timestamp_year_i
timestamp_month_i
timestamp_day_i
...

などが表示されます。

ここからは、Lucene Query Syntaxを利用してフィールドを指定した検索も試してみます。


14. 日本語のフレーズ検索

例えば、

週刊少年サンデー

というまとまりを検索してみます。

run_cli(
    """search('text_ja:"週刊少年サンデー"', 5)"""
)

Luceneでは、

"週刊少年サンデー"

のように引用符で囲むことでフレーズ検索ができます。

さらに今回は、

text_ja:

を付けて、

text_ja:"週刊少年サンデー"

としています。

つまり、

日本語テキストフィールド text_ja から「週刊少年サンデー」というフレーズを検索する

という意味です。


15. カテゴリを指定して検索する

Wikipediaデータには category_s というカテゴリフィールドがあります。

例えば「恋愛漫画」というカテゴリを検索します。

run_cli(
    'search("category_s:恋愛漫画", 10)'
)

全文検索だけでなく、このような構造化されたフィールドも同じLuceneインデックスで検索できます。


16. 全文検索とカテゴリを組み合わせる

次は条件を組み合わせます。

run_cli(
    """search('text_ja:"高橋留美子" AND category_s:恋愛漫画', 10)"""
)

Lucene Query Syntaxの、

AND

を使っています。

つまり、

本文に「高橋留美子」
AND
カテゴリに「恋愛漫画」

の両方を満たす文書を検索しています。

全文検索と構造化データを自然に組み合わせられるところは、Luceneを利用するメリットの一つです。


17. OR検索も試してみる

検索語を変えて実験してみましょう。

run_cli(
    """search('category_s:恋愛漫画 OR category_s:ギャグ漫画', 10)"""
)

Lucene Query Syntaxでは、

AND
OR
NOT

などを利用できます。

Google Colabならセルをコピーして条件を少しずつ変更できるので、Lucene Query Syntaxの練習にも使えます。


18. 日付範囲検索を試す

今回のデータには、

timestamp_dt

という日付フィールドがあります。

2026年1月1日以降の文書を検索してみます。

run_cli(
    'search("timestamp_dt:[2026-01-01 TO *]", 10)'
)

Luceneの、

[2026-01-01 TO *]

は、

2026-01-01 以上

という範囲を表しています。

文字列検索だけでなく、このようなRange Queryも利用できます。


19. 年フィールドでも検索する

日付から生成された、

timestamp_year_i

という整数フィールドもあります。

例えば2020年から2026年までを検索します。

run_cli(
    'search("timestamp_year_i:[2020 TO 2026]", 10)'
)

このように、

テキスト
Keyword
Integer
Date

を一つのインデックスで扱うことができます。


20. 集計可能なフィールドを見る

次は検索とは少し違うことをしてみます。

run_cli("aggregatable_fields")

view() で分析できるフィールド一覧が表示されます。

今回注目するのは、

category_s

です。


21. Wikipediaで多いカテゴリを見る

カテゴリの上位を表示してみます。

run_cli(
    'view("category_s", 20)'
)

今回のデータでは、例えば、

日本の漫画家
存命人物
生年未記載
継続中の作品
恋愛漫画
...

といったカテゴリが多く出現します。

これは検索ではありません。

Luceneインデックスに入っているデータを、

どの値が多いのか?

という観点から眺めています。

全文検索用に作ったインデックスを、簡単なデータ探索にも利用できます。


22. 少ないカテゴリを除外する

view() の3番目の数値は min_count として利用できます。

例えば、

run_cli(
    'view("category_s", 20, 3)'
)

とすると、出現数が少なすぎるカテゴリを除外できます。

カテゴリの種類が多いデータでは便利です。


23. 「高橋留美子」に特徴的なカテゴリを見る

view() と検索条件を組み合わせることもできます。

run_cli(
    """view("category_s", 'text_ja:"高橋留美子"', 20, 3)"""
)

これは、

1. 「高橋留美子」を検索
2. ヒットした文書のcategory_sを集計
3. 全文書での出現状況と比較

という処理です。

単純な検索では、

どの文書がヒットしたか

を見ることができます。

一方 view() を組み合わせると、

ヒットした文書群にはどのような特徴があるか

という方向からデータを見ることができます。

テキスト検索と簡単なテキスト分析を同じインデックス上で試せます。


24. 好きな検索を試してみる

ここまで動いたら、あとは自由にクエリを書き換えてみます。

例えば、

run_cli(
    'search("category_s:SF漫画", 10)'
)
run_cli(
    'search("category_s:少女漫画", 10)'
)
run_cli(
    """search('text_ja:"タイムスリップ"', 10)"""
)

などです。

さらに、

run_cli(
    """search('text_ja:"タイムスリップ" AND category_s:恋愛漫画', 10)"""
)

のように条件を組み合わせても構いません。

このように、セルをコピーしてクエリを少しずつ変えて実験できるところが、Google Colabとの相性のよい部分です。


25. CLIを終了する

最後に、

run_cli("exit")

としたいところですが、exit の後には次の >> プロンプトが出ないため、終了だけは直接送ります。

cli.sendline("exit")
cli.expect(pexpect.EOF)
print(cli.before)

次のように表示されます。

bye

これでCLIセッションは終了です。


26. 最初から最後までの流れ

今回行ったことをまとめると、とてもシンプルです。

Step 1: インストール

!pip install -q nlp4j-local-search==0.6.1

Step 2: データ取得

!wget -q \
  https://nlp4j-2.sakura.ne.jp/data/wiki/jawiki-20260801-pages-articles_compact_manga.jsonl.gz \
  -O /content/jawiki_manga.jsonl.gz

Step 3: CLI起動

import pexpect

cli = pexpect.spawn(
    "nlp4j-local-search --lang ja",
    encoding="utf-8",
    timeout=120,
)

cli.expect(">> ")
print(cli.before)

Step 4: データロード

run_cli(
    'load("/content/jawiki_manga.jsonl.gz")',
    timeout=300,
)

Step 5: 日本語検索

run_cli(
    'search("高橋留美子", 5)'
)

Step 6: フィールド検索

run_cli(
    'search("category_s:恋愛漫画", 10)'
)

Step 7: 日付検索

run_cli(
    'search("timestamp_dt:[2026-01-01 TO *]", 10)'
)

Step 8: 集計

run_cli(
    'view("category_s", 20)'
)

ここまで、検索サーバーを起動する操作はありません。


Apache LuceneをNotebookで気軽に試す

Apache Luceneは、Elasticsearch、OpenSearch、Apache Solrなどの基盤として長年利用されている全文検索ライブラリです。

一方、Lucene自体はJavaライブラリなので、

PythonのNotebookから少しだけLuceneを試したい

という用途では、少し距離があります。

nlp4j-local-search では、

Google Colab
      ↓
Python / CLI
      ↓
Apache Lucene

という形で、その距離を短くすることを目指しています。

今回の例では、

  • サーバー構築なし
  • Dockerなし
  • 日本語検索
  • 約3万件のWikipediaデータ
  • Lucene Query Syntax
  • Keywordフィールド
  • Date / Integerの範囲検索
  • カテゴリ集計

までをGoogle Colab上で順番に試せました。


Colabとの相性

今回あえてGoogle Colabを使ったのは、検索ライブラリの説明とNotebookの相性がよいと考えているからです。

例えば、

search("高橋留美子")

を実行して結果を見た後、

search("漫画家")

に変える。

さらに、

search("category_s:恋愛漫画")

を試す。

その次に、

view("category_s", 20)

を実行する。

というように、一つずつ結果を確認しながら検索機能を理解できます。

READMEを読むだけの場合と違って、

この条件だと何が出るのだろう?

と思った瞬間に、その場でセルを書き換えて試せます。

検索エンジンやNLPの実験では、このインタラクティブ性はかなり便利だと思います。


まとめ

今回は、nlp4j-local-search 0.6.1 をGoogle Colabから利用して、Apache Luceneによる日本語全文検索を試しました。

ポイントは次の通りです。

  • Apache Luceneを利用
  • 日本語全文検索に対応
  • Pythonから利用可能
  • 対話型CLIを利用可能
  • Google Colabで実行可能
  • Elasticsearch / OpenSearch / Solrのサーバー構築は不要
  • Docker不要
  • .jsonl.gz を直接ロード可能
  • Lucene Query Syntaxを利用可能
  • フレーズ検索が可能
  • フィールド検索が可能
  • AND / ORなどの条件検索が可能
  • 日付・数値のRange Queryが可能
  • view() でカテゴリなどを探索可能

特にGoogle Colabでは、

インストール
↓
データ取得
↓
ロード
↓
1つ検索
↓
結果を見る
↓
クエリを変える
↓
もう一度検索

という流れをNotebook上でステップ・バイ・ステップに試せます。

Luceneそのものに興味がある方だけでなく、

日本語のJSONLデータを手軽に全文検索してみたい

という用途でも試してもらえればと思います。


Links

PyPI

https://pypi.org/project/nlp4j-local-search/0.6.1/

GitHub

https://github.com/oyahiroki/nlp4j-local-search

今回使用した日本語Wikipediaサンプルデータ

https://nlp4j-2.sakura.ne.jp/data/wiki/jawiki-20260801-pages-articles_compact_manga.jsonl.gz

Qiita tags

Python
Lucene
自然言語処理
全文検索
GoogleColab
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?