1

コンテキスト:注文システムの分析システムに取り組んでいます。1日あたり約100,000件の注文があり、分析は過去Nか月(たとえば100日)にわたって実行する必要があります。関連するデータはメモリに収まります。N日後、すべての注文がメモリキャッシュから削除され、過去1日が削除されます。注文は作成または更新できます。

  1. 従来のアプローチでは、を使用しConcurrentHashMap<Date, Queue<Order>>ます。毎日、過去N日を超える日付を表すキーの値が削除されます。しかし、もちろん、Guavaを使用することの全体的なポイントはこれを回避することです。編集:に変更さMapれましたConcurrentHashMap。理論的根拠については、質問の最後を参照してください。

  2. Guavaコレクションを使用するMultiMap <Date, Order>と、より簡単になります。エビクションも同様で、明示的に実装されています。

  3. 実装は魅力的にCache見えますが(結局のところ、私はキャッシュを実装しています)、エビクションオプションについてはよくわかりません。立ち退きは1日に1回だけ発生し、キャッシュの外部から開始するのが最適です。キャッシュで注文の経過時間を確認する必要はありません。キャッシュがMultiMapを使用するかどうかさえわかりません。この場合、これは適切なデータ構造だと思います。

したがって、私の質問は次のとおりです。MultiMapのセマンティクスを使用および公開し、特に必要なルール(「N日より古いすべての注文を削除する」)を使用して、外部から制御されるエビクションを許可するキャッシュを使用することは可能ですか?

重要な説明として、私は興味がありLoadingCacheませんが、一括ロードが必要です(アプリケーションを再起動する必要がある場合は、データベースから、過去N日間の注文でキャッシュにデータを入力する必要があります)。

編集:地図は同時である必要があることを言及するのを忘れました。注文が入ってくると、同じ顧客や場所などの以前の注文に対してライブで評価されます。

EDIT2:グアバの問題135に出くわしました。MultiMapは同時ではないようです。

4

3 に答える 3

2

Cacheここではaもhereも使用しませんMultimap。私は両方が好きで使用していますが、ここで得られるものはあまりありません。

  • エントリを手動で削除したいので、の機能はCacheここでは実際には使用されません。
  • あなたはConcurrentHashMap<Date, Queue<Order>>、ある意味でより強力な、を検討していますMultimap<Date, Order>

Cache異なる立ち退き基準について考え、いつでもそのエントリのいずれかを失いたいと思った場合は、を使用します1で問題ありません。

ConcurrentMap<Date, Dequeue<Order>>あなたはあなたがまたは多分または何でも必要であることに気付くかもしれませんConcurrentMap<Date, YouOwnQueueFastSearchList<Order>>。これはおそらく何らかの方法で管理できますがMultimap、私見では単純ではなく複雑になります。

Cache「ここで使うと何が得られるのMultimap?」と自問します。私には、あなたが必要とするすべてのものについての昔ながらのConcurrentMap申し出のように見えます。


1決して、これがグアバで起こることを示唆しているわけではありません。反対に、立ち退きの理由(容量、有効期限など)がない場合は、のように機能しConcurrentMapます。あなたが説明したことは、Mapというよりはむしろのように感じられるというだけCacheです。

于 2012-11-26T22:06:44.163 に答える
1

IMHO最も簡単な方法は、注文の日付を注文レコードに含めることです。(すでにフィールドであると思います)キャッシュをクリーンアップする必要があるのは1日1回だけなので、それほど効率的である必要はなく、適度にタイムリーです。

例えば

public class Main {
    static class Order {
        final long time;

        Order(long time) {
            this.time = time;
        }

        public long getTime() {
            return time;
        }
    }

    final Map<String, Order> orders = new LinkedHashMap<String, Order>();

    public void expireOrdersOlderThan(long dateTime) {
        for (Iterator<Order> iter = orders.values().iterator(); iter.hasNext(); )
            if (iter.next().getTime() < dateTime)
                iter.remove();
    }

    private void generateOrders() {
        for (int i = 0; i < 120000; i++) {
            orders.put("order-" + i, new Order(i));
        }
    }

    public static void main(String... args) {
        for (int t = 0; t < 3; t++) {
            Main m = new Main();
            m.generateOrders();
            long start = System.nanoTime();
            for (int i = 0; i < 20; i++)
                m.expireOrdersOlderThan(i * 1000);
            long time = System.nanoTime() - start;
            System.out.printf("Took an average of %.3f ms to expire 1%% of entries%n", time / 20 / 1e6);
        }
    }
}

プリント

Took an average of 9.164 ms to expire 1% of entries
Took an average of 8.345 ms to expire 1% of entries
Took an average of 7.812 ms to expire 1% of entries

100,000の注文の場合、これには約10ミリ秒かかると予想されますが、深夜の静かな時間帯にはそれほど多くはかかりません。

ところで:OrderIdを時間で並べ替えると、これをより効率的にすることができます。;)

于 2012-11-26T12:51:06.090 に答える
0

ある種のソートされたリストを使用することを検討しましたか?それはあなたがとどまるのに十分新鮮なものに当たるまであなたがエントリーを引っ張ることを可能にするでしょう。もちろん、これはそれがあなたの主要な機能であることを前提としています。最も必要なのがハッシュマップを使用したO(1)アクセスである場合、私の答えは当てはまりません。

于 2012-11-26T13:06:50.567 に答える