0

Snappy-javaを使用してJSONデータをエンコードしており、結果をデータベースのvarchar列に保存したいと考えています。
データベースは、ISO-8859-1エンコーディングのOracleデータベースです。
データを挿入するときにエンコードの問題が発生します。一部の文字はOracleによって認識されないようです。

圧縮データを挿入する前に、Base64エンコーディングを使用することで回避策を見つけました。その後、問題なく取得できます:)

それに関する問題は、Base64エンコーディングにより、保存するデータの長さが長くなり、Snappyで得られる節約が減ることです...

だから私の質問は:Base64でエンコードせずにそのデータを保存するにはどうすればよいですか?varcharを使用する理由は、テーブルにアクセスせずにoracleインデックスを使用してテーブルにアクセスできるようにするためです(パフォーマンスは間違いなく問題です)。

他の圧縮アルゴリズムも試しましたが、すべて同じ問題があるようです。yEncも調べましたが、Javaエンコーダーが見つかりません。さらに、yEncにリストされているすべての問題を理解できるかどうかわからないため、yEncを使用するのは少し気が進まない。

助けてくれてありがとう!

4

4 に答える 4

1

データを圧縮しています。圧縮の結果は、ほとんどの場合、テキストではなくバイナリデータになります...Snappyの場合もそうだと思います。

バイナリデータをテキストとして正確に保存するには、Base64などを使用する必要があります。あなたは文字を持っていません-あなたはバイトを持っています。

圧縮されたテキストを効率的に格納するには、データベース列をテキスト指向のタイプではなくバイナリ指向のタイプ(基本的にはCLOBではなくBLOB)に変更する必要があります。

于 2012-07-27T14:24:49.623 に答える
0

問題の文字は、OracleDBの制御文字である可能性があります。いずれの場合も、varcharとしてではなく、「text」または「clob」としてデータを保存することを検討することをお勧めします。

それが足りない場合は、データを挿入する前に、データにジップまたはハフマンタイプのコンプレッサーを使用する必要があります。次のようなもので遊んだことがありますか:Javaで文字列を圧縮する方法は?

于 2012-07-27T14:24:57.267 に答える
0

テキストフィールドの代わりにバイナリフィールドを使用するというJonSkeetの答えは、明らかな解決策です。

本当にテキストフィールドを使用する必要がある場合は、最初に実験して、そこに何を格納できるかを確認してください。私の推測では、ゼロバイト以外の任意のバイトを格納できます。ゼロバイトは可変長文字列を終了するために使用されます。バイト0x01..0xffを含む長さ255の文字列を格納し、それを取得して、それらのバイトが正確に返されるかどうかを確認できます。そうした場合、避けるべき唯一のバイトはゼロです。

私の理論が正しければ、データの拡張を制限してゼロを取り除く簡単な方法がいくつかあります。最も簡単なのは、0に到達したら、0x80、0x01を送信することです。0x80を取得したら、0x80、0x81を送信します。次に、デコード時に0x80が表示された場合は、次のバイトを取得して1を減算します。これにより、ストリームが平均1%(0.78%)未満拡張されます。

拡張の問題を完全に最小限に抑える場合は、より洗練されたコーディングスキームを使用するとより良い結果が得られます。

于 2012-07-27T15:14:30.820 に答える
0

よろしくお願いします!

私はついに回避策を見つけました。charではなくbytesを格納しているので、BLOBを使用してデータを格納します。BLOBの問題は、インデックスを作成できないことです。別の方法は、RAWタイプの列を使用することです。バイトを格納し、索引付け可能です。残念ながら、小さすぎます(2000バイト)。したがって、私の場合の答えは、データをBLOBに格納し、データが4000バイトを超えることはないため、2つのRAWタイプのインデックスを介してデータにアクセスすることです。

インデックスは次のようになります。

CREATE INDEX blob_to_raw_prd_ix 
ON product (product_id, 
            substr_dt(blob_summary,2000,1), 
            substr_dt(blob_summary,2000,2001));

どこ

  • blob_summaryは、データを格納するBLOB列です。
  • substr_dtは、ユーザー定義の決定論的関数です(以下で定義)。

    関数の作成または置換substr_dt(str BLOB、buffer_size int、offset int)RETURN RAW DETERMINISTIC IS BEGIN RETURN dbms_lob.substr(str、buffer_size、offset); 終わり;

データにアクセスするには、エイリアスを使用してproduct_idとフィールドをクエリする必要があります。

SELECT     /*+ index(blob_to_raw_prd_ix) */ product_id, 
                                            substr_dt(blob_summary, 2000, 1) AS summary1, 
                                            substr_dt(blob_summary, 2000, 2001) AS summary2
FROM       product
WHERE      (product_id = ?);

この場合、summary_1はblobの最初の2000バイトを表し、summary2は最後の2000バイトを表します。2つの配列summary1とsummary2で連結を使用して、blobのコンテンツを取得します。

これはJdbcで機能しますが、Hibernateでは(まだ)機能させることができませんでした。データを解釈する前に再処理する必要があるため、これはこれまでで最高のソリューションではありません。ただし、エンコーディングスペースのオーバーヘッドなしでデータアクセスの問題を解決します。

于 2012-08-02T14:18:03.280 に答える