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