2012-09-05 6 views
7

単純に、タイムスタンプ、メッセージIDなどのフィールドが考慮されるべきではないので、キャッシュが正しいキーを選択する方法を変更する必要がありますキーを取得する。 キーオブジェクトの実際のハッシュ関数は、自分のコードですでに認識されているため、変更できません。
Guavaキャッシュでは可能ですか?そして回避策はありますか?

これは私の設定です:キーを挿入するときのカスタム等価/ハッシュ

CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).recordStats(). 
    expireAfterWrite(DEFAULT_AGE, TimeUnit.DAYS).build(
    new CacheLoader<Request, Response>() { 
     @Override 
     public Response load(Request request) { 
      return request.getResponse(); 
     } 
    }); 

そしてこれが(私のコードのどこかで使用)私のハッシュ関数である:

public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + code; 
    result = prime * result + messageID; // <= **this one shouldn't evaluated** 
    result = prime * result + Arrays.hashCode(payload); 
    result = prime * result + (int) (timestamp^timestamp >>> 32); // <= **this one shouldn't evaluated** 
    result = prime * result + (type == null ? 0 : type.hashCode()); 
    result = prime * result + version; 
    return result; 
} 

はところで、独自の実装を使用してキャッシュのこの種でありますハッシュ関数(例えば、イントロスペクションを通じて)、またはデフォルトのものを使用していますか?

** EDIT: **
としては、回答に指摘し、この結果を達成するための最良の方法は、ラッパークラスです。
私のソリューション

/** 
* Nested class to store a request as a key in the cache. It is needed to 
* normalize the variable fields of the normal requests. 
*/ 
private static final class CachedRequest extends Request { 

    private static CachedRequest fromRequest(Request request) { 
     // set only the fields that cannot change between two same requests 
     // ... 
    } 

    @Override 
    public int hashCode() { 
     HashFunction hashFunction = Hashing.md5(); 
     HashCode hashCode; 
     // ... 
     return hashCode.asInt(); 
    } 

    @Override 
    public boolean equals(Object obj) { 
      // coherent with hashCode() 
      // ... 
    } 
} 
+0

私はそれが独自のハッシュ実装を使用した場合、非常に有用なユーティリティであるとは思いません。 – jtahlborn

+0

また、「実際の」オブジェクトを認識するためにすでに使用されているため、私はhash()関数を変更できません。 – jtahlborn

+0

実際に私はこの機能を追加するつもりはありませんが、誰かがこのような状況に対処する方法を知っていれば。 – Hamal000

答えて

13

あなたは、単にCachedRequestが必要なフィールドに基づいてhashCode()equals()を実装し、ラップRequestへのアクセスを提供する場所、CachedRequestオブジェクトにあなたのRequestオブジェクトをラップすることができます。あなたがキャッシュに

1

あなたはハッシュ関数を変更できない場合(なぜ私はまだ理解していないが)、あなたは例えば、「ラッパー」キーを使用する必要があります。

public class RequestKey { 
    private final Request _req; 

    public int hashCode() { 
    // use appropriate Request fields here 
    } 

    public boolean equals(Object o) { 
    return ((this == o) || ((o != null) && (getClass() == o.getClass()) && _req.equals(((RequestKey)o)._req))); 
    } 
} 
+0

ハッシュはレガシーコードであり、ハッシュは既に別の場所で使用されているため、変更できません。 – Hamal000

+0

@ Hamal000 - 私はそれを理解しています。ただし、ハッシュコードからフィールドを削除しても、他の場所でその有用性が低下してはいけません(データベースなどにこれらのハッシュコードを永続的に保存しない限り) – jtahlborn

+0

1つのフィールドを削除すると、ハッシュ関数がオブジェクトをマッピングしているスペースを縮小しますこれは問題ではありません... 残念ながら、私の場合、ハッシュは、この関数を使ってクライアント側のどこかでidとして使用されます。 – Hamal000

1

私はかなりよ確かに、グアバでは不可能です。カスタム等価性を使用するいくつかの合法的なケースがありますが、CacheBuilderMapMakerで処理するにはあまりにも稀です。 com.google.common.base.Equivalenceもありますが、内部でのみ使用されます(hereおよびhereも参照)。

あなたは、あなたが検索に使用するフィールドの外に鍵を所有して作る、またはequalshashCodeあなたが望む方法を定義する別のオブジェクトであなたのRequestをラップする必要があります。

デフォルトequals/hashCodeは異なる何かが使用されますのみの場合は、(softKeysがこれ以上存在している)weakKeysであり、そしてそれは==/System.identityHashCodeコンボです。どちらの場合でも、同値を自由に選択することはできません。

+0

+1弱鍵 – Hamal000

+1

「等価」は公開されています:http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Equivalence.html – fry

+0

@fry:確かにそうですが、 ( 'Maps.difference'の中で)公開されるのは1つだけです。 – maaartinus

関連する問題