ネストされたマップと結合キー


8

私が現在取り組んでいるプロジェクトでは、ユーザーの年齢(大人、子供など)に応じて3つの異なるタイプの価格がありました。したがって、DBには次のようなテーブルがありました。

PRICES
type     Amount
A         20
B         15
C         ..
D         ..

最初は4種類の価格しかなかったので、コードには次のようなものがありました。

Map<String, BigDecimal> prices = new HashMap<String, BigDecimal>();

キーは価格タイプでした。

最近、彼らはすべての価格タイプに3つのサブタイプを追加する新しいビジネスルールを追加したので、次のようになります。

PRICES
type   subtype  Amount
A          1      20
A          2      15
A          3      ..
B          1      ..
B          2      ..
...        ..     ..

次の2つのオプションのどちらが良いと思いますか、そしてその理由は?

ネストされたマップ

Map<String, Map<String, BigDecimal>> prices;

ここで、キーは価格タイプとサブタイプです。

prices.get(type).get(subtype);

結合キー

最初と同じマップ:

Map<String, BigDecimal> prices;

キーを連結して、さまざまな価格にインデックスを付けます。

prices.get(type+"_"+subtype);

これは設計上の問題であり、Code Reviewにはコードが不十分です。
200_success 14

小さなメモ:提案された組み合わせキーは、将来的に問題を引き起こす可能性があります。たとえば、1つの価格タイプに「_」が必要になる場合があります。代わりにclass PriceKey{ PriceType type; PriceSubtype subtype; }鍵を持つことを検討してください。これは簡単にさらに拡張できます
Caleth

回答:


8

ネストされたキーと結合されたキーの両方に場所があります。bowmoreは複合キーのpro引数とネストされたマップのcon引数を提供します。忠実な反対を提供させてください:

複合マップキーは、特定の既知のアイテムを検索する場合に最適です。

ネストされたマップは、タイプAのすべてのバリエーション、種類、およびサブタイプをすばやく検索する必要がある場合に適切に機能します。たとえば、A(対B、C、...)を選択することは、意思決定ツリーの最初のステップになる場合があります。ユーザーまたはアルゴリズムまたは何かがAを選択したら、Aのサブタイプについてのみ知る必要があり、B..ZまたはB..ZZZZZはもはや重要ではありません。

これで、サブサーチのための非常にタイトで効率的なルックアップ構造を扱っています。複合キーを使用してこれを行おうとすると、最終的に全テーブルスキャンを実行することになります[ (key, value) for (key, value) in prices.items() if key.startswith('A') ]。それがありますない効率的な運用、およびマップは、すべての大規模である場合に遅くなります。

ネストされたマップは、ネストレベルの数が増える場合にもうまく機能します。問題の構造はすでにからtypeに拡張されてい(type, subtype)ます。次のリビジョンが必要になる可能性はあります(type, subtype, variation)(type, subtype, version)?その場合、ネストされたマッピングアプローチをきれいに拡張できます。ただし、これは特に上記の「簡単なサブサーチ」の利点と比較して、スタイル上の2次的な利点です。


正直なところ、複合キーのインクリメンタル検索では、SortedMapを使用して「テーブルスキャン」を回避できます。
ボウモア2014

マップをソートすることにより、複合キーの検索特性を改善できます。ただし、この方法ですべてのスキャンを回避することはできません。たとえば、テーブル内のキー「RXR_1_a」またはソートされた10,000キーのマッピングを見つけるには、「RXR_ *」が開始および終了するテーブルインデックスを見つける必要があります。バイナリサーチを使用しても、これはゼロ時間ではありません。また、key.startswith('RXR')私が述べたのと同じテストが必要です。ネストされたマップは常にO(1)操作であり、マップの事前ソートのオーバーヘッドや文字列比較を必要としません。
ジョナサンユーニス

そうです、私はあなたが「テーブルスキャン」スタイルの操作を避けることができると言ったばかりです。私の回答では、この種の検索の場合、DBに直接クエリする方が簡単であることも指摘します。どちらのアプローチでも、最初のフィールドで始まらない部分キーの検索で問題が発生します。DBは、追加のインデックスを使用してこれを軽減できます。
ボウモア2014

SortedMapは完全な線形検索を回避できますが、高コストの検索はできません。データベースでの操作のポーンがどのように役立つかはわかりません。おそらくクライアントコードを簡略化するかもしれませんが、遅い外部リクエストと余分なデータ構造(操作をさらに効率的にするために必要なインデックス)を犠牲にしてください。ネスト構造には確かにいくつかの欠点がありますが、バックアップデータベースのサポートの有無にかかわらず、自己完結型で非常に効率的です。
ジョナサンユーニス2014

バイナリ検索はどのように高コストの検索ですか?
ボウモア2014

6

マップのネストは避けてください。それらはスケーリングが難しく、コードが非常に冗長になり、ネストされたすべてのジェネリック宣言が続いていると読みにくくなります。

さらに重要なことに、Javaのマップは多くのメモリを消費する傾向があります。さらに多くのマップをマップに追加しても、メモリ消費の問題が悪化するだけです。

最後に、複合キーを使用するマップの方が推論しやすいです。

複合キーを使用すると、最も一般的なケースでは作業が楽になりますが、難しいこともあります。たとえば、特定の主要コンポーネントのすべての価格を取得しますが、その結果をマップから抽出するのではなく、データベースから直接クエリする可能性が高くなります。


私はあなたの発言に同意しますが、場合によってはマップのネストが避けられないことがあり、そのシナリオではJavaでマップを操作するための良い方法が見つかりませんでした。Javaで一般的な何か、特にJSONファイルを読み取る/操作する必要がある場合は常に、アプリケーションでファイルの構造をハードコーディングする場合を除き、マップをネストする必要があります。
froginvasion 2016

1

これは、「どの実装が最適か」ではなく、「どの抽象化で作業する必要があるか」に関係しています。

複合キーとマップのマップの両方に長所と短所があり、それらはすべてパフォーマンスのドメイン(つまり、速度/メモリ使用量)の範囲内にあります。これらは機能に違いはありません。どちらも2つの値を取り、以前の「プット」値を返します。

それらは機能的に同等なので、最初にすべきことはそれらを抽象化することです。どちらが良いか心配しないでください。必要なすべてのメソッドを含むDoubleKeyedMapインターフェースを作成し、それをコードで使用します。次に、最速で実行できる実装を記述します。

アプリケーションを作成し、複合キーの実装が最初のキーで高速にフィルタリングしないこと、または最適化を行った場合にマップのマップが大量のメモリを使用していることがわかった場合にのみ。

時期尚早の最適化は、すべての悪の根源です。抽象化しないほうが悪い。


よく言った。抽象化しないほうが悪いです!大好きです
ザックバルテル

0

どちらのオプションも私の意見では良くありません。別のサブタイプを持つようにビジネスロジックが再び変更された場合はどうでしょうか。

私があなたがすることを提案するのは以下です:

  1. Typeこのテーブルは次のようなテーブル呼び出しに代理キーを使用しますType(INT auto_inc id, VARCHAR(255) name, VARCHAR(255) desc, INT status, etc)
  2. あなたにはPrice、テーブルに外部キーを使用しType、それは次のようになりますので、上記の表Price(INT type_id, INT price)
  3. タイプの削除をサポートしていないことを確認してください。inactiveぶら下がっている参照が原因で削除が本当の頭痛の種になるため、タイプをマークするだけです

これで、ユーザーロジックとビジネスロジックは、あらゆるタイプのサブタイプの組み合わせをスキーマに追加できます。彼らがする必要があるのは、Typeテーブルに新しい行を作成し、古いテーブルを変更nameまたは変更することdescです。

あなたのケースでは、ユーザーがタイプの名前を変更するでしょうA型にA_1呼ばれる新しいタイプの追加、A_2のために、新たな価格を設定するA_2ように15

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.