0

ユーザー向けのテーブルを作成し、その目的を追跡したいと考えています。目標自体は、1000ではないにしても、100のオーダーであり、独自のテーブルに保持されますが、誰がそれらを完了したかはわかりません。使用可能な目標を定義するだけです。

Objective:
ID  |  Name   |  Notes  |
----+---------+---------+
    |         |         |

これで、Java環境では、ユーザーは目的のためにjava.util.BitSetを使用できるようになります。だから私は行くことができます

/* in class User */
boolean hasCompletedObjective(int objectiveNum) {
    if(objectiveNum < 0 || objectivenum > objectives.length())
        throw new IllegalArgumentException("Objective " + objectiveNum + " is invalid. Use a constant from class Objective.");
    return objectives.get(objectivenum);
}

内部的には、BitSetはlong[]を使用してストレージを実行します。私のダービーデータベースでこれを表す最良の方法は何でしょうか?それらは実際にはユーザーの要素であるため、可能な限りAppUserテーブルの列に保持することをお勧めします。

Derbyは(私の知る限り)配列をサポートしていません。列の制限はわかりませんが、特にデータベースに次のようなクエリを実行しないことがわかっているため、1000列の場合は問題があるようです。

SELECT *
FROM AppUser
WHERE AppUser.ObjectiveXYZ

保存とビットセットへのマーシャリングの両方のオプションは何ですか?java.util.BitSetの実行可能な代替手段はありますか?一般的なアプローチに欠陥はありますか?私はアイデアを受け入れています!

ありがとう!

*編集:可能であれば、テーブルの変更ではなく、データの変更のみで目標を追加できるようにしたいと思います。しかし、繰り返しになりますが、私はアイデアを受け入れています!

4

2 に答える 2

1

【付け髭をつける】

ビットセットをBLOBとして格納します。単純にシリアル化することから始めて、より多くのスペース効率が必要な場合は、データベースに向かう途中で DeflaterOutputStream を介して結果をプッシュしてみてください。空間効率と時間効率を向上させるには、 FastBitで使用されるビットマップ圧縮方法を試してください。これは、ビットセットを 31 ビットのチャンクに分割し、すべてゼロのチャンクをランレングス エンコードして、リテラルとラン チャンクを 32 ビット ワードにパックします。識別ビット付き。

データベースから取得した ResultSet がまだ開いている間に目的のビットセットのみを確認することがわかっている場合は、Blob インターフェイスをラップし、getBytes の上に get を実装する新しいビットセット クラスを記述します。これにより、いくつかの特定のビットをチェックするために BLOB 全体をメモリに読み込む必要がなくなり、少なくともすべての値を調べたい場合に、ビットセットに別のバッファを割り当てる必要がなくなります。圧縮されたビットセットでこれを機能させるには、かなりの工夫が必要であることに注意してください。

このアプローチでは、参照整合性が得られず、ユーザーと目的の関係を照会する機能がなく、将来のデータのさまざまな用途に対する柔軟性がほとんどないことに注意してください。これはまさにDon Knuth が警告した種類のものです

于 2011-02-21T20:18:59.897 に答える
1

これを行うためのオーソドックスな方法は、ビットセットをまったく使用しません。ユーザー用のテーブル、目標用のテーブル、およびユーザーの目標を示す結合テーブルがあります。何かのようなもの:

create table users (
    id integer primary key,
    name varchar(100) not null
);

create table objectives (
    id integer primary key,
    name varchar(100) not null
);

create table user_objective (
    user_id integer not null references users,
    objective_id integer not null references objectives,
    primary key (user_id, objective_id)
);

ユーザーが目的を持っているときはいつでも、その事実を示す行を結合テーブルに入れます。

ユーザーのビットセットに結果を取得する場合は、結合テーブルを介して目的のテーブルにユーザーの外部結合を実行します。これにより、すべての目的の行が返されます。これには、たとえば、次の単一の列があります。結合された目標ごとに 1、または結合されていない場合は 0。

オーソドックスなアプローチは、ビットセットではなく、Java 側でセットを使用することです。これは、結合テーブルに非常にうまくマップされます。このようにすることを検討しましたか?

メモリ消費が心配な場合、セットは、ユーザーが実際に持っている目的ごとに約 1 つのポインターを使用します。ビットセットは、考えられる目的ごとにビットを使用します。ほとんどの JVM には 32 ビット ポインターがあります (64 ビット ポインターを持つのは、古いまたは巨大なヒープの 64 ビット JVM だけです)。そのため、各ユーザーが平均して可能な目的の 1/32 未満である場合、セットはより少ないメモリを使用します。この情報をこれらの構造のいずれよりもコンパクトに格納できるグルーヴィーなデータ構造がいくつかありますが、それは別の質問に任せましょう。

于 2011-02-20T00:36:36.900 に答える