アペフチ

Groonga新リリース自慢会 6.0.2

Groonga新リリース自慢会 6.0.2@クラウドワークスに参加して来た。

Groongaは毎月29日に新バージョンをリリースしているので、今日は一足早いお披露目ということになる。主な変更点は次のページにまとまっている:

Groonga 6.0.2リリース

主に@ktouさんが自慢していってくれたのだけど、追加や修正されたうちnaoa_yさんが実装した物も多かったようで、一緒に参加していたnaoa_yさんに自慢してもらった物も結構あった。今回の個人的な目玉はそのうちの多段ドリルダウンだった。自ら詳しい紹介を書いているのでそちらを参照されたい:Groonga 6.0.2から多段ドリルダウンが利用可能に。naoa_yさんはユーザーにとってキャッチーな新機能を実装してくれることが多くありがたいことだ。

もう一つの個人的な目玉は、PGroongaの各種機能追加だ:1.0.7: 2016-04-24。PGroongaは使っていないけど個人的にこの機能は欲しくて、GitHubでイシューを上げていたりする: [RFC]API to retrieve query position in document #437。早くGroonga(と言うかgroonga-httpd)にも入ってほしい。

日記のコメント用にHypothes.isを埋め込んでみた

Hypothes.isのバー この日記は自分が読んでいて邪魔だなと感じる物はなるべく置かないようにしていて、ツイートとかシェアとかのボタンがないのはそのため。コメントについてはずっと迷っていたけど、まあ、置いてみようかということにした。静的サイトジェネレーターと組み合わせるコメントソリューションとしてはDISQUSがデファクトスタンダード(ドファクトスタンダール?)だと思うけど、気になっていたHypothes.isを試すことにした。ページ右端に見えているエリアがそれだ。タイトルを隠してしまったりして「邪魔」なのは間違いないのだけど好奇心が勝ってしまった。タイトルの位置は後で調整する(かも)。

記事中の文章を選択するとアノテーションとハイライトのアイコンが現れる。 記事の適当な所を選択するとAnnotateとHighlightのアイコンが出てきて、コメントを付けたりハイライトしたりできる。他人が付けたコメントについては、右端のバーを引っ張りだすことで見られる(コメントを残す時に、ここに現れてもよいかどうかを選べる)。

Hypothes.isはウェブページなどにアノテーションを付けられるようにしようというプロジェクトで、そのための埋め込みJavaScriptコードやChrome拡張なんかを作っている。アノテーションというのは、ページの全体や一部分をハイライトしたり、コメントを付けたりすること。はてなスターとかはてブみたいなイメージ。W3CがWeb Annotationとしてこうしたニーズのための仕様を策定中だったりする(Hypothes.isがWeb Annotationに従っているかは分からない。その前身のOpen Annotationに従ってはいたと思うので、プランとして追従するつもりはあるんだと思う)。アノテーションについてはかざかざさんの素晴らしい記事を参照されたい。リンク先末尾の「関連エントリ」もぜひ辿ってほしい。

日本よっ!これがOpen Annotationだっ!!

ウェブページごと(URIごと)にフィードを吐いているので、このページに付けられたコメント一覧」みたいな物をページ末尾に付けたりすることはできるので、後でちょっとやってみようと思う(邪魔だったら公開しない)。

しかしまあ、Hypothes.isへの登録が必要なところとか、そもそもこの日記でコメントを残したいのかとか、使われるか不安はあるが、まあ、いいか。

取り敢えずPDFを全文検索するシステムのための最少ステップ

Groongaで学ぶ全文検索 2016-03-25に行って来た。

今日は、仕事でPDFを全文検索できるようにしたいから話を聞きに来たという参加者がいたので、PDFを全文検索できるよう、Groongaのデータベースを作るまでをその場でやった。

まず、PDFを全文検索するために必要なことの概要を説明した。

全文検索できるようにするまでの概要

PDFを全文検索するには

  1. 全文検索できるようにするための準備(データベースの構築)
  2. データベースを使って全文検索をする

という二段階が必要になる。

準備は、

  1. PDFからテキストを抜き出す
  2. テキストをGroongaに突っ込む
  3. Groongaが(勝手に)インデックスを作る

という手順に分解できる。ここのところ僕が説明したのだけど、「テキストをGroongaに突っ込む」のところ、「どのような形で」というのが抜けていて、そこがぴんとこなかったようだ。あとで@ktouさんとの質疑応答で「PDFのパスとかのメタデータと一緒に(JSONとかのフォーマットにして)突っ込む」と言ったところでぴんときたようだった。

手順に戻って、全文検索の実行のところ。

  1. 検索語をGroongaに与える
  2. Groongaがその語を含むPDFのパス(とか、ページ番号とかの付随的な物)を返す

ということになる。

PDFを全文検索できるようにする

ここまで説明した所で、手元のPDFファイルを使って実際にデータベースの作成から検索してみるまでを@ktouさんがやって見せてくれた。時間も限られているので、「本文に関する検索をして、そのPDFのパスが得られるようにする」というのを目標にした。

1. テーブルを作る

コマンドラインでテーブルを作る(暗黙に、Groongaはテーブルの形でデータを表現しているということになる)。

table_create pdfs \
  TABLE_HASH_KEY \
  ShortText

ShortTextのところは、ハッシュテーブルのキーの型を決めている。

こんなファイルを作って、groongaコマンドに入力すると、pdfsテーブルが出来る。

まずデータベース(ファイル)を作る。

% groonga -n /tmp/grn

次にファイルに書いたコマンドを読み込ませる。

% groonga /tmp/grn < /tmp/table-create.grn

これでテーブルが出来る。ただ、今はハッシュテーブルのキーのところにしかデータが保存できないので、PDF本文を保存する場所をこのテーブルのカラムとして作る。

column_create pdfs body \
  COLUMN_SCALAR \
  Text

COLUMN_SCALARの所はCOLUMN_SCALARCOLUMN_VECTORかが選べて、このカラムに入るのが分割できない単位なのか、配列のようにその単位を複合させた物なのかで選ぶ。今回は、一つのキー(PDFファイルのパス)に複数の本文が入ることはないので、スカラーにしている。

データを入れる

で、実際にデータを入れる。

その前に、PDFからテキストの形式にしないといけない。更に、Groongaは(コマンドでは)JSONフォーマットでデータを入力するので、データを加工しなければならない。

ここでは、Poppler付属のpdftotextコマンドで抽出したテキストをファイルに保存して、それを使ってRubyで、ファイルのパス情報と一緒にJSONにしていた。本題ではないので割愛。以下のようなファイルをRubyで作って、groongaコマンドに読み込ませる。

load --table pdfs
[
  {
    "_key": "path/to/pdf"
    "body": "でかい本文"
  }
]

インデックス無しでの検索

Groongaはインデックスを作らないでも検索できる。

select --table pdfs \
  --query body:@API

@APIの所が、(その前にあるbodyカラムに対して)APIで検索する、という指定になっている。インデックスが無い時は、ただの線形検索になる。@ktouさんの手元のPDF、手元のGroongaで試したところ、この検索には60ミリ秒くらい掛かった。インデックスを作って使うとこれより速いはずなので後で試してみる。

インデックスを作る

RDBMSでは、インデックスを張るには単に張りたいカラムを指定すればよかったが、Groongaではより検索方法に合わせた柔軟なインデックスが作れるように、色々パラーターを指定しながら自分でインデックスを作る。そのインデックスは、上でやったようなテーブルとして作る。

が、初めての時などはおすすめの設定があるので取り敢えずテンプレとしてそれを使えばよい。

table_create terms \
  TABLE_PAT_KEY \
  ShortText \
  --default_tokenizer TokenBigram \
  --normalzer NormalizarAuto

全文検索する時は、(pdfsテーブルでハッシュテーブルにしていたところに相当するところが)パトリシアトライというのがおすすめなので、TABLE_PAT_KEYと書く。これはこのまま使っておけばよい。「terms」というのがテーブル名なので、ここだけ気分によって変えればよい。

次はカラム。

column_create terms body_index \
  COLUMN_INDEX|WITH_POSITION \
  pdfs \
  body

これもテンプレで、「body_index」は変えてよい。名前から想像付くように、pdfsテーブルのbodyカラムのためのインデックスだからこの名前になっている。分かりやすいのがいいだろう。「pdfs」は、pdfsテーブルに対するインデックスということを意味し、「body」はその中のbodyカラムへのインデックスだということをGroongaに教えている。

これでさっきのように

select --table pdfs \
  --query body:@API

すると、今度は0.2ミリ秒程度で検索結果が返って来た。二桁の差が付いたことになる(PDF結構でかくて、1MiBくらいあった)。

あとは、アプリケーションの要件に合わせてウェブUIを付けたりすると出来上がりだ。

参考までに既にGroongaを使ったPDF検索アプリケーションとしてhonyomiがあって、検索結果からそのまま読み始めたりできるので便利。