在分布式环境中,我如何将多个键映射到相同的值?

huangapple 未分类评论51阅读模式
英文:

How can I map multiple keys to the same value in a distributed environment?

问题

在一个分布式环境中,我想讨论实现将多个键映射到同一个值的映射映射的方法。

一种实现方法(我不喜欢)(使用Java):

class ConcurrentMultiKeyMap<K1, K2, V> {
    HashMap<K1, K2> map1to2 = new HashMap<>();
    HashMap<K2, K1> map2to1 = new HashMap<>();
    HashMap<K1, V> mapToV = new HashMap<>();

    public synchronized V put(K1 k1, K2 k2, V v) {
        K2 previousK2 = map1to2.get(k1);
        K1 previousK1 = map2to1.get(k2);
        mapToV.remove(previousK1);
        map1to2.remove(previousK1);
        map2to1.remove(previousK2);
        map1to2.put(k1, k2);
        map2to1.put(k2, k1);
        return mapToV.put(k1, v);
    }

    // ... (其他方法的定义,省略)

    @Test public void demonstration() {
        // ... (演示代码,省略)
    }
}

有人知道更好的解决方案吗?如果能够适用于可变数量的键并使用智能锁定方案,将会获得额外的加分。

注意:所需的解决方案需要允许分别通过任一键进行访问。因此,传统的复合键(Composite Key)无法工作,因为仅使用任一键无法计算哈希码。

提前感谢您的回答。

英文:

I'd like to discuss implementions of a map mapping multiple keys mapped to the same value in a distributed environment.

One method of implementing this(that I don't like) (in Java):

class ConcurrentMultiKeyMap&lt;K1, K2, V&gt; {
    HashMap&lt;K1, K2&gt; map1to2 = new HashMap&lt;&gt;();
    HashMap&lt;K2, K1&gt; map2to1 = new HashMap&lt;&gt;();
    HashMap&lt;K1, V&gt; mapToV = new HashMap&lt;&gt;();

    public synchronized V put(K1 k1, K2 k2, V v) {
        K2 previousK2 = map1to2.get(k1);
        K1 previousK1 = map2to1.get(k2);
        mapToV.remove(previousK1);
        map1to2.remove(previousK1);
        map2to1.remove(previousK2);
        map1to2.put(k1, k2);
        map2to1.put(k2, k1);
        return mapToV.put(k1, v);
    }
    synchronized void remove(K1 k1) {
        K2 k2 = map1to2.remove(k1);
        map2to1.remove(k2);
        mapToV.remove(k1);
    }
    synchronized void remove(K2 k2) {
        K1 k1 = map2to1.remove(k2);
        map1to2.remove(k1);
        mapToV.remove(k1);
    }
    synchronized V get(K1 k1) {
        return mapToV.get(k1);
    }
    synchronized V getBy2(K2 k2) {
        K1 k1 = map2to1.get(k2);
        if(k1 != null)
            return getBy1(k1);
        else
            return null;
    }



    public synchronized boolean containsBy1(K1 k1) {
        return map1to2.containsKey(k1);
    }
    public synchronized boolean containsBy2(K2 k2) {
        return map2to1.containsKey(k2);
    }
    public synchronized V[] values(V[] empty_va) {
        return mapToV.values().toArray(empty_va);
    }
    public synchronized int size() {
        return mapToV.size();
    }
    public synchronized boolean isEmpty() {
        return mapToV.isEmpty();
    }

    public synchronized void clear() {
        mapToV.clear();
        map1to2.clear();
        map2to1.clear();
    }

    @Override public synchronized String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(&quot;BadConcurrentMultiKeyMap{&quot;);
        for(Map.Entry&lt;K1, V&gt; entry : mapToV.entrySet()) {
            builder.append(&quot;(&quot;);
            K1 k1 = entry.getKey();
            K2 k2 = map1to2.get(k1);
            V v = entry.getValue();
            builder.append(&quot;k1=&quot;).append(k1).append(&quot;,&quot;);
            builder.append(&quot;k2=&quot;).append(k2).append(&quot;,&quot;);
            builder.append(&quot;v=&quot;).append(v);
            builder.append(&quot;), &quot;);
        }
        if(!isEmpty()) builder.delete(builder.length()-2, builder.length());
        builder.append(&quot;}&quot;);
        return builder.toString();
    }

    @Test public void demonstration() {
        ConcurrentMultiKeyMap&lt;Integer, String, String&gt; map = new ConcurrentMultiKeyMap&lt;&gt;();

        map.put(1, &quot;1&quot;, &quot;v1&quot;);
        map.put(2, &quot;2&quot;, &quot;v2&quot;);
        assertEquals(&quot;v1&quot;, map.getBy1(1));
        assertEquals(&quot;v1&quot;, map.getBy2(&quot;1&quot;));
        assertEquals(&quot;v2&quot;, map.getBy1(2));
        assertEquals(&quot;v2&quot;, map.getBy2(&quot;2&quot;));
        assertNull(map.getBy1(3));
        assertNull(map.getBy2(&quot;3&quot;));

        map.removeBy1(1);
        assertNull(map.getBy1(1));
        assertNull(map.getBy2(&quot;1&quot;));

        map.removeBy2(&quot;2&quot;);
        assertNull(map.getBy1(2));
        assertNull(map.getBy2(&quot;2&quot;));


        map.put(1, &quot;A&quot;, &quot;v1&quot;);
        System.out.println(&quot;map = &quot; + map);
        map.put(2, &quot;A&quot;, &quot;v2&quot;);
        System.out.println(&quot;map = &quot; + map);
        map.removeBy1(1);
        System.out.println(&quot;map = &quot; + map);
        System.out.println(&quot;map.mapToV = &quot; + map.mapToV);
        System.out.println(&quot;map.map1to2 = &quot; + map.map1to2);
        System.out.println(&quot;map.map2to1 = &quot; + map.map2to1);

        map.clear();

        map.put(1, &quot;A&quot;, &quot;v1&quot;);
        System.out.println(&quot;map = &quot; + map);
        map.put(2, &quot;A&quot;, &quot;v2&quot;);
        System.out.println(&quot;map = &quot; + map);
        map.removeBy2(&quot;A&quot;);
        System.out.println(&quot;map = &quot; + map);
        System.out.println(&quot;map.mapToV = &quot; + map.mapToV);
        System.out.println(&quot;map.map1to2 = &quot; + map.map1to2);
        System.out.println(&quot;map.map2to1 = &quot; + map.map2to1);
    }
}

Does anyone knwo a better solution? Bonus points if it were to work for a variable number of keys and use a smart locking scheme.

NOTE: The solution is required to allow access by either key separately. So a traditional CompositeKey does not work, since the hash code cannot be calculated with only either key.

Thanks in advance

huangapple
  • 本文由 发表于 2020年4月7日 04:20:51
  • 转载请务必保留本文链接:https://java.coder-hub.com/61068308.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定