Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
9
Help us understand the problem. What is going on with this article?
@ukitiyan

【Groongaで学ぶ全文検索 2016-02-12】実例を元にしたGroongaのテーブル設計

More than 5 years have passed since last update.

はじめに

  • 1ヶ月ぶりに本勉強会に参加しました。ワークショップ感もありつつ、物凄く充実した勉強会でした。
  • 参加者の方の発言でgroonga-httpdの話題にも触れました。Mroongaとの連携等で面白そうな使い方出来そうなので、簡単に記載してます。
  • あとGo言語の話題がちょっと出たので、試しに書いてみました。これも良い勉強になりました。

勉強会で学んだこと

groonga-httpd

  • http経由でGroongaにアクセスしたい場合に便利
  • エンジンはGroonga、フロントはnginxで動いてる
  • 実体はnginxにモジュール機能があって、モジュールとしてGroongaが動いてる

    • 因みにMroongaはMySQLのモジュール機能で動いてる
    • 勿論、エンジンはGroongaで同じモジュール
    • つまり、バックオフィスでMroongaでデータ突っ込んで、フロントの検索をhttpdでアクセスするとかも出来る!
    • これはオモシロイ!
  • Groongaの独自実装でhttpアクセス出来る

    • 軽量で速さ重視なので、Basic認証とかhttpsとか出来ない

実例を元にした全文検索エンジン(Groonga)のテーブル設計

背景

  • 今回の勉強会のお題として、@yamamaijpさんが国立国会図書館のデータを全文検索してみたとのことでその設計レビューをすることになりました。
  • 今までの勉強会の勉強成果を実践してるというのは素晴らしいなと素直に思います。
  • 自分も実践したい。(いや、する!)

要件

  • インフラは、Vagrant上のCentOS。
  • 国立国会図書館の以下TSVデータを何がしかで全文検索する。
    • 裏要件として、日本酒に関する情報を素早く検索したいという思いがあるようです(笑)
  • TSVには以下の内容が含まれている。

    NDLサーチ書誌詳細画面URL,ISBN,セットISBN,ISSN,ISSN-L,DOI,NDLJP(国立国会図書館が付与する永続的識別子),タイトル,巻次・部編番号,部編名,別タイトル,シリーズタイトル,版,著者,出版者,出版地,出版年月日,受理日,目次,注記,言語,大きさ・容量,記録形式,掲載誌名,掲載巻,掲号,掲載通号,提供元書誌詳細画面のURL,一次資料へのリンク,原資料へのリンク,関連資料,異版を持つ,掲載誌情報,目次・記事,別の記録形式である,別の記録形式を持つ
    
  • ここからダウンロード。
    http://www.ndl.go.jp/jp/data/data_service/jnb/ebej_tsv.html

  • レコード数は34.9万件。

設計時に考えたこと

  • 何が返ってきてほしいか。
  • 何で検索したいか。

レビュー結果

テーブル作成

table_create

table_create --name Books --flags TABLE_HASH_KEY --key_type ShortText
  • 後述するが前提として、データロードの際、key項目にはURLをセットしている。
  • 上記前提からすると、key_typeにShortTextを使ってるのは正しい。
  • flagsの指定の観点として、更新があるテーブルでキーが必要か?必要な場合、ハッシュテーブルか?パトリシアトライか?で決めるべき。
    • 基本更新がなく、キーが不要な場合は、TABLE_NO_KEYを指定する
    • キーが必要でハッシュテーブルの場合は、TABLE_HASH_KEYを指定する
    • キーが必要でパトリシアトライの場合は、TABLE_PAT_KEYを指定する(自分的には、TABLE_PAT_KEYはインデックステーブルの時、指定すると理解しました)
  • 今回は洗い替えが基本で、更新が不要なテーブルのためTABLE_NO_KEYで良いかもしれない。

カラム作成

column_create

column_create Books title --flags COLUMN_SCALAR --type ShortText
column_create Books author --flags COLUMN_SCALAR --type ShortText
  • titleは単一の値なので、flagsに指定しているCOLUMN_SCALARの指定は正しい。
  • authorはもしかしたら、複数の値がある可能性があるので、COLUMN_VECTORの方が良いかもしれない(レビュー後、データを確認したところ複数値は存在しないことが確認されたためCOLUMN_SCALARで正しかった)。
  • COLUMN_VECTORを指定した場合、データ導入時の値は配列型にする必要がある。
  • つまり観点としては、カラムに複数の値が入るかどうか(配列かどうか)。
    • flagsには、COLUMN_SCALAR、COLUMN_VECTORが指定可能。
    • COLUMN_SCALARの場合、単一の値が格納できる。
    • COLUMN_VECTORの場合、複数の値を格納できる。

データロード

load

$ echo "load --table Books" > data.load
$ cat data.json >> data.load
$ groonga books.db < data.load
  • tsv to jsonのスクリプトを自作した◎
  • key値としてURLを指定したが、これは少し問題との指摘があがった。
    • ShortTextの上限である4KiB超える可能性がある
    • ISBN(アイエスビーエヌ、International Standard Book Number)の方が適当
    • それかURLをハッシュ化して、それをキーにする
    • ただし、今回のようなデータでURLが4KiBを超えることは無いのでは?との意見が過半数を超えたため、これも問題ないとの結論に至りました。
  • 「tsv to jsonのスクリプトはGo言語で書きたいよね!」と@ktouさんが発言していたので、書きました!

    • ukitiyan/tsvToJson
    • @yamamaijpさんへ、今回のケースでは、以下のようなコマンドで欲しいJsonが手に入ると思いますよ。

      $ go run tsvToJson.go digital_20160130.tsv digital.json 0:_key 7:title 14:author

データ検索(転置インデックス作成前)

select

select Books --query title:@日本酒
  • 日本酒で検索◎
  • title:@日本酒はtitleカラムを日本酒で全文検索するという宣言。
  • @を外すと完全一致検索になる。
  • インデックス作成していないのでフルスキャンになるが、検索結果として0.6秒とこの時点で流石のベンチ。

転置インデックステーブル作成

table_create

table_create --name Indexes --flags TABLE_PAT_KEY --key_type ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
  • flagsに指定したTABLE_PAT_KEYは、以下の要件を満たすことが出来たので結果的に正しい。
    • 要件:日本酒バンザイという書籍を「日本酒」じゃなくて「酒」という検索ワードで検索したい。
    • bigramは右記のようにトークナイズする日本 本酒 酒バ バン ンザ ザイ
    • TABLE_PAT_KEYを指定すると、高度な検索が出来て、前方一致もその高度な検索に含まれてるので検索される。
    • TABLE_PAT_KEYは、主キーをパトリシア木に格納することを指示しているようです。
    • 因みにMySQL 5.7からInnodbでサポートされたNgramの場合、上記は検索されない。

転置インデックスカラム作成

column_create

column_create --table Indexes --name book_title --flags COLUMN_INDEX|WITH_POSITION --type Bookes --source title
  • typeは対象のテーブルを指定、sourceはそのテーブルのインデックス化したいカラムを指定するので、今回の指定は正しい。
  • flagsに指定したWITH_POSITIONは、検索時にトークナイズされたワードが隣り合ってるのかが考慮される。つまり全文検索したい時は必須なオプション(忘れずに設定すること)
  • 隣り合ってるかどうかを考慮するのはフレーズ検索と言って、これは以前勉強した内容です。

データ検索(転置インデックス作成後)

select

select Books --query title:@日本酒
  • 検索結果のレコード数は転置インデックス作成前と一致しており、検索速度が向上しているのでインデックスの作成は問題ないと言える。
  • 結果的に転置インデックス作成したら、検索結果が20倍の速さで返ってきたということで、これまた流石。

さいごに

  • RDBSに慣れ親しんだ自分がこの勉強会を聞いていて、全体的にキーをテーブルと呼称して、バリューをカラムと呼称しているよう感じた。
  • これは KVS Groonga的には正解な考え方で森大二郎さんのスライドでもその通り紹介されている。
  • 今回の勉強会は時間オーバーする程の盛り上りだったのですが、あと2時間は行けたな−と感じたのでした。
9
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ukitiyan
ここでの記載内容は個人の見解であり、所属する団体の公式見解ではありません。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
9
Help us understand the problem. What is going on with this article?