[groonga-dev,02165] Re: Groongaにpdfのようなバイナリファイルを格納したい

Back to archive index

Kouhei Sutou kou****@clear*****
2014年 3月 3日 (月) 11:02:59 JST


須藤です。

In <CA+vpKirWc0UaWFr__as72iG7bu2P7HYh7soWoi1d+0tZrMkn=w****@mail*****>
  "[groonga-dev,02164] Groongaにpdfのようなバイナリファイルを格納したい" on Sat, 1 Mar 2014 21:33:07 +0900,
  ongaeshi <ongae****@gmail*****> wrote:

> # Droonga 1.0 おめでとうございます!

ありがとうございます!

> Groonga(実際にはRroonga)にpdfやxmlといったバイナリファイルを
> 格納したいと考えています。
> 
> バイナリを検索したいという要求は特になくて、
> ストレージとして他のカラムと一緒に格納して
> Webアプリでpdfとして表示出来るようにしたいと思っています。
> 
> http://groonga.org/ja/docs/reference/types.html
> 
> 辺りに目を通してみたのですが、上手い方法が思いつきませんでした。

いくつかやり方があるんですが、個人的には最後の「Groongaには
パスだけ格納する」がオススメです。

1. Text型を指定して、カラムにアクセスする前後で
   Groonga::Contextのエンコーディングを
   Groonga::Encoding::NONEにする

Groongaでは「1文字」を正しく扱うためにエンコーディング情報を
持っています。これは、カラム毎に持っている情報ではなく、
Groonga::Contextが持っている情報です。1つのGroonga::Context
は同時に1つのデータベースしか扱えないので、データベース内で
エンコーディングを統一する必要があります。

と、ここまでが一般論です!実は、Groonga::Contextのエンコーディ
ングは処理の途中で変えてもよいです。ただし、整合性を保つのは
ユーザー側の責任です。例えば、UTF-8のテキストを扱うときに
Shift_JISというエンコーディングを指定されてうまく動かなくて
も、それはGroongaの責任ではなく、ユーザー側の責任、というこ
とです。

実際、Mroongaはコンテキストのエンコーディングをころころ変え
ています。これは、MySQLではカラム毎にエンコーディングが違う
からです。

RroongaでもGroonga::Contextのエンコーディングを変えることがで
きるので、バイナリーデータを格納したいカラムをText型で定義し、
そのカラムにアクセスする前後でエンコーディングを変更します。

  original_encoding = context.encoding
  context.encoding = :none
  record[binary_column_name] # -> ASCII-8BIT String
  context.encoding = original_encoding

欠点は見ての通り、めんどくさいことです。メソッドでラップして
いるならアリだとは思います。例えばこんな感じです。

  class User
    def initialize(record)
      @record = record
    end

    def profile_image
      change_encoding(:none) do
        @record.profile_image
      end
    end

    def profile_image=(data)
      change_encoding(:none) do
        @record.profile_image = data
      end
    end

    private
    def context
      @record.table.context
    end

    def change_encoding(encoding)
      _context = context
      original_encoding = _context.encoding
      begin
        _context.encoding = encoding
        yield
      ensure
        _context.encoding = original_encoding
      end
    end
  end

あと、Groongaのメモリ使用量が増えます。バイナリーデータは総
じて大きめなので、そこそこ増える気がします。

2. Text型を指定して、カラムの値はBASE64にしてASCIIのテキスト
   として扱う

バイナリーデータだったとしても、Groongaに入れるときにはバイナ
リーデータではなくするという方法です。

これも、めんどくさいのとメモリ使用量が増えることが欠点です。
あと、データ量が3割くらい増えます。あと、あと、変換処理が入る
ので多少遅くなると思います。

  require "base64"

  class User
    def initialize(record)
      @record = record
    end

    def profile_image
      Base64.decode64(@record.profile_image)
    end

    def profile_image=(data)
      @record.profile_image = Base64.encode64(data)
    end
  end


3. Groongaにはパスだけ格納する

バイナリーデータはファイルとして保存し、Groongaにはそのファ
イルのパスだけ格納します。

これだと、Groongaのメモリ使用量は増えません。が、別の意味で
めんどくさくなります。ファイルを管理しなければいけないからで
す。サーバーが複数台になったらさらに大変です。

ただし、もし、PDFファイルがすでにファイルシステム上にあるファ
イルなら、そんなに面倒ではありません。プログラムがファイルの
作成・削除などをする必要がないからです。

また、大抵のWebアプリケーションフレームワークはファイルを返す
ための専用のAPIを持っているので、Groongaにパスしか入っていな
くても、WebアプリケーションがPDFを返すのは簡単なはずです。例
えば、Sinatraならattachmentやsend_fileといったAPIがあります。

Rroongaは1台のマシンで動くものなのでファイル管理がそんなに面
倒にならない気がします。なので、この方法がオススメです!


-- 
須藤 功平 <kou****@clear*****>
株式会社クリアコード <http://www.clear-code.com/> (03-6231-7270)

Groongaサポート:
  http://groonga.org/ja/support/
パッチ採用はじめました:
  http://www.clear-code.com/recruitment/
コミットへのコメントサービスはじめました:
  http://www.clear-code.com/services/commit-comment.html




groonga-dev メーリングリストの案内
Back to archive index