Thanks, Amir! I responded in the ticket. Let's move the discussion there. On Sun, Aug 14, 2016 at 11:51 AM, Amir Akhmedov <[email protected]> wrote:
> I updated the ticket with design details. Can you please review it and put > your comments? > > https://issues.apache.org/jira/browse/IGNITE-640 > > On Fri, Aug 12, 2016 at 4:03 PM, Amir Akhmedov <[email protected]> > wrote: > > > I think we need both Collection and List interfaces as Guava has. > > Dmitriy provided a really good example for List based Multimap. Set based > > implementation also has a plenty use cases like guarantee for value > > uniqueness or performance reasons for remove(key, value), > > containsEntry(key, value) methods > > > > On Aug 12, 2016 3:41 PM, "Dmitriy Setrakyan" <[email protected]> > > wrote: > > > >> One of the good use cases for MutliMap is time-series data, which > assumes > >> ordering. This means that we need to store values for the key exactly in > >> the same order as they are provided. If we do that, then returning lists > >> should not be a problem. No? > >> > >> On Fri, Aug 12, 2016 at 9:38 AM, Valentin Kulichenko < > >> [email protected]> wrote: > >> > >> > Vova, Denis, > >> > > >> > How do you see this API-wise? What if user actually wants to get a > >> sublist > >> > of values, without fetching the whole collection? Are you suggesting > to > >> > have subinterfaces, similar to Guava [1]? > >> > > >> > [1] > >> > https://google.github.io/guava/releases/snapshot/api/ > >> > docs/com/google/common/collect/ListMultimap.html > >> > > >> > -Val > >> > > >> > On Fri, Aug 12, 2016 at 12:14 PM, Denis Magda <[email protected]> > >> wrote: > >> > > >> > > Fully agree with Vovan’s suggestion. It’s not a good idea to hard > code > >> > the > >> > > interface to the usage of List. > >> > > > >> > > Moreover, I would provide an implementation of the IgniteMultimap > with > >> > > TreeSet under the hood out of the box. A user will be able to use > this > >> > > implementation if performance of multi map updates is more critical > >> for a > >> > > use case. > >> > > > >> > > — > >> > > Denis > >> > > > >> > > > >> > > > On Aug 12, 2016, at 12:01 PM, Vladimir Ozerov < > [email protected] > >> > > >> > > wrote: > >> > > > > >> > > > Correct me if I am wrong, but I always thought that multimap is > >> about > >> > > > associating multiple values with a single key without explicit > >> > > > specification on how these values are stored. E.g.: > >> > > > Google Guava - > >> > > > https://google.github.io/guava/releases/snapshot/api/ > >> > > docs/com/google/common/collect/Multimap.html#get(K) > >> > > > Apache Commons - > >> > > > https://commons.apache.org/proper/commons-collections/ > >> > > apidocs/org/apache/commons/collections4/MultiValuedMap.html#get(K) > >> > > > > >> > > > I would rather return *Collection*, but with ability to specify > >> > > underlying > >> > > > data structure using some factory. > >> > > > > >> > > > On Fri, Aug 12, 2016 at 6:35 PM, Dmitriy Setrakyan < > >> > > [email protected]> > >> > > > wrote: > >> > > > > >> > > >> Amir, > >> > > >> > >> > > >> It is great that you decided to pick this ticket. I suggest to > >> handle > >> > > the > >> > > >> design discussions in the ticket itself, as Jira allows for > better > >> > code > >> > > >> formatting. It still makes sense, though, to notify the dev list > >> that > >> > > you > >> > > >> have updated the ticket, so folks remember to look at it. > >> > > >> > >> > > >> D. > >> > > >> > >> > > >> On Thu, Aug 11, 2016 at 7:26 PM, Amir Akhmedov < > >> > [email protected] > >> > > > > >> > > >> wrote: > >> > > >> > >> > > >>> Hi guys, > >> > > >>> > >> > > >>> I noticed that IgniteMultimap waits too long to be implemented > >> and I > >> > > >>> decided to pick it up :-) > >> > > >>> > >> > > >>> For now I want to bring to community up a draft version for > >> > > >> IgniteMultimap > >> > > >>> interface. Will appreciate any feedback and once it's fine I > will > >> > start > >> > > >> its > >> > > >>> implementation > >> > > >>> > >> > > >>> > >> > > >>> package org.apache.ignite; > >> > > >>> > >> > > >>> import org.apache.ignite.lang.IgniteCallable; > >> > > >>> import org.apache.ignite.lang.IgniteRunnable; > >> > > >>> > >> > > >>> import java.io.Closeable; > >> > > >>> import java.util.*; > >> > > >>> > >> > > >>> public interface IgniteMultimap<K, V> extends Closeable { > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns the list of values to which the specified key is > >> > mapped, > >> > > >>> * or {@code null} if this map contains no mapping for the > key. > >> > > >>> * > >> > > >>> * @param key the key whose associated values are to be > >> returned > >> > > >>> * @return the list of values to which the specified key is > >> > mapped, > >> > > >>> * or {@code null} if this map contains no mapping for the > key. > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> */ > >> > > >>> public List<V> get(K key); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns the value at a certain index to which the > specified > >> key > >> > > >>> is mapped, > >> > > >>> * or {@code null} if this map contains no mapping for the > key. > >> > > >>> * > >> > > >>> * @param key the key whose associated values are to be > >> returned > >> > > >>> * @param index index to lookup > >> > > >>> * @return the value at a certain index to which the > specified > >> key > >> > > >>> is mapped, > >> > > >>> * or {@code null} if this map contains no mapping for the > key. > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> * @throws IndexOutOfBoundsException if the index is out of > >> range > >> > > >>> (index < 0 || index >= list.size()) > >> > > >>> */ > >> > > >>> public V get(K key, int index); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns the values for specified range of indexes, between > >> min > >> > > and > >> > > >>> max > >> > > >>> * to which the specified key is mapped, or {@code null} if > >> this > >> > > >>> map contains > >> > > >>> * no mapping for the key. > >> > > >>> * > >> > > >>> * @param key the key whose associated values are to be > >> returned > >> > > >>> * @param min min index to lookup > >> > > >>> * @param max max index to lookup > >> > > >>> * @return the values for specified range of indexes, between > >> min > >> > > and > >> > > >>> max > >> > > >>> * to which the specified key is mapped, or {@code null} if > >> this > >> > > >>> map contains > >> > > >>> * no mapping for the key. > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> * @throws IndexOutOfBoundsException if either of indexes min > >> or > >> > > >>> max is out of > >> > > >>> * range (index < 0 || index >= list.size()) > >> > > >>> */ > >> > > >>> public List<V> get(K key, int min, int max); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns the list of values for specified indexes to which > >> the > >> > > >>> specified key > >> > > >>> * is mapped, or {@code null} if this map contains no mapping > >> for > >> > > the > >> > > >>> key. > >> > > >>> * @param key the key whose associated values are to be > >> returned > >> > > >>> * @param indexes the indexes to lookup > >> > > >>> * @return the list of values for specified indexes to which > >> the > >> > > >>> specified key > >> > > >>> * is mapped, or {@code null} if this map contains no mapping > >> for > >> > > the > >> > > >>> key. > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> * @throws IndexOutOfBoundsException if either of indexes is > >> out > >> > of > >> > > >>> * range (index < 0 || index >= list.size()) > >> > > >>> */ > >> > > >>> public List<V> get(K key, Iterable<Integer> indexes); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns the list of values for a collection of keys to > which > >> > > >>> the keys are mapped. > >> > > >>> * {@code null} will be added to resulting list if this map > >> > > >>> contains no mapping for the key. > >> > > >>> * @param keys collection of keys > >> > > >>> * @return the list of values for a collection of keys to > which > >> > > >>> the keys are mapped. > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> * {@code null} will be added to resulting list if this map > >> > > >>> contains no mapping for the key. > >> > > >>> */ > >> > > >>> public Map<K, List<V>> getAll(Collection<K> keys); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns a value at a certain index for a collection of > keys > >> to > >> > > >>> which the keys are mapped. > >> > > >>> * {@code null} will be added to resulting list if this map > >> > > >>> contains no mapping for the key. > >> > > >>> * @param keys collection of keys > >> > > >>> * @param index the index to lookup > >> > > >>> * @return a value at a certain index for a collection of > keys > >> to > >> > > >>> which the keys are mapped. > >> > > >>> * {@code null} will be added to resulting list if this map > >> > > >>> contains no mapping for the key. > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> * @throws IndexOutOfBoundsException if the indexes is out of > >> > > >>> range (index < 0 || index >= list.size()) > >> > > >>> */ > >> > > >>> public Map<K, V> getAll(Collection<K> keys, int index); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns the list of values for the range of indexes, > between > >> > > >>> min and max for a collection > >> > > >>> * of keys to which the keys are mapped. {@code null} will be > >> > > >>> added to resulting list if this > >> > > >>> * map contains no mapping for the key. > >> > > >>> * @param keys collection of keys > >> > > >>> * @param min min index to lookup > >> > > >>> * @param max max index to lookup > >> > > >>> * @return the list of values for the range of indexes, > between > >> > > >>> min and max for a collection > >> > > >>> * of keys to which the keys are mapped. {@code null} will be > >> > > >>> added to resulting list if this > >> > > >>> * map contains no mapping for the key. > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> * @throws IndexOutOfBoundsException if either of indexes min > >> or > >> > > >>> max is out of > >> > > >>> * range (index < 0 || index >= list.size()) > >> > > >>> */ > >> > > >>> public Map<K, List<V>> getAll(Collection<K> keys, int min, > int > >> > max); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns the list of values for specified indexes or a > >> > > >>> collection of keys to which the keys are > >> > > >>> * mapped. {@code null} will be added to resulting list if > this > >> > > >>> map contains no mapping for the key. > >> > > >>> * @param keys collection of keys > >> > > >>> * @param indexes the indexes to lookup > >> > > >>> * @return the list of values for specified indexes or a > >> > > >>> collection of keys to which the keys are > >> > > >>> * mapped. {@code null} will be added to resulting list if > this > >> > > >>> map contains no mapping for the key. > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> * @throws IndexOutOfBoundsException if either of indexes is > >> out > >> > > >>> of range (index < 0 || index >= list.size()) > >> > > >>> */ > >> > > >>> public Map<K, List<V>> getAll(Collection<K> keys, > >> > > >>> Iterable<Integer> indexes); > >> > > >>> > >> > > >>> /** > >> > > >>> * Iterate through all elements with a certain index. > >> > > >>> * @param index the index to lookup > >> > > >>> * @return Iterator through all elements with a certain > index. > >> > > >>> * @throws IndexOutOfBoundsException index is out of range > for > >> any > >> > > >>> list of values > >> > > >>> * (index < 0 || index >= list.size()) > >> > > >>> */ > >> > > >>> public Iterator<Map.Entry<K, V>> iterate(int index); > >> > > >>> > >> > > >>> /** > >> > > >>> * Clears the multimap. Removes all key-value pairs. > >> > > >>> */ > >> > > >>> public void clear(); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns {@code true} if this multimap contains a mapping > for > >> > > >>> the specified key. > >> > > >>> * > >> > > >>> * @param key key whose presence in this map is to be tested > >> > > >>> * @return {@code true} if this map contains a mapping for > the > >> > > >>> specified key > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> */ > >> > > >>> public boolean containsKey(K key); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns {@code true} if this multimap contains at least > one > >> > > >>> key-value pair > >> > > >>> * with the value {@code value}. > >> > > >>> * > >> > > >>> * @param value value whose presence in this map is to be > >> tested > >> > > >>> * @return {@code true} if this multimap contains at least > one > >> > > >>> key-value pair > >> > > >>> * with the value {@code value}. > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> */ > >> > > >>> public boolean containsValue(V value); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns whether the multimap contains the given key-value > >> pair. > >> > > >>> * > >> > > >>> * @param key key whose presence in this map is to be tested > >> > > >>> * @param value value whose presence in this map is to be > >> tested > >> > > >>> * > >> > > >>> * @return {@code true} if the multimap contains the > key-value > >> > > >>> pair, {@code false} otherwise > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> */ > >> > > >>> public boolean containsEntry(K key, V value); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns a {@link Set} view of the mappings contained in > this > >> > map. > >> > > >>> * > >> > > >>> * @return a {@link Set} view of the mappings contained in > this > >> > map. > >> > > >>> */ > >> > > >>> public Set<Map.Entry<K, V>> entrySet(); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns the locally owned set of keys. > >> > > >>> * > >> > > >>> * @return the locally owned set of keys. > >> > > >>> */ > >> > > >>> public Set<K> localKeySet(); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns a {@link Set} view of the keys contained in this > >> map. > >> > > >>> * > >> > > >>> * @return a {@link Set} view of the keys contained in this > >> map. > >> > > >>> */ > >> > > >>> public Set<K> keySet(); > >> > > >>> > >> > > >>> /** > >> > > >>> * Associates the specified value with the specified key in > >> this > >> > > >>> multimap > >> > > >>> * > >> > > >>> * @param key key with which the specified value is to be > >> > associated > >> > > >>> * @param value value to be associated with the specified key > >> > > >>> * @return {@code true} if the method increased the size of > the > >> > > >>> multimap, or > >> > > >>> * {@code false} if the multimap already contained the > >> key-value > >> > > pair > >> > > >>> and > >> > > >>> * doesn't allow duplicates > >> > > >>> * @throws ClassCastException if the class of the specified > >> key or > >> > > >>> value > >> > > >>> * prevents it from being stored in this map > >> > > >>> */ > >> > > >>> public boolean put(K key, V value); > >> > > >>> > >> > > >>> /** > >> > > >>> * Stores a key-value pair in this multimap for each of > {@code > >> > > >>> values}, all > >> > > >>> * using the same key, {@code key}. Equivalent to (but > >> expected to > >> > > be > >> > > >>> more > >> > > >>> * efficient than): <pre> {@code > >> > > >>> * > >> > > >>> * for (V value : values) { > >> > > >>> * put(key, value); > >> > > >>> * }}</pre> > >> > > >>> * > >> > > >>> * <p>In particular, this is a no-op if {@code values} is > >> empty. > >> > > >>> * > >> > > >>> * @return {@code true} if the multimap changed > >> > > >>> * @throws ClassCastException if the class of the specified > >> key or > >> > > >>> value > >> > > >>> * prevents it from being stored in this map > >> > > >>> */ > >> > > >>> public boolean putAll(K key, Iterable<? extends V> values); > >> > > >>> > >> > > >>> /** > >> > > >>> * Stores all key-value pairs of {@code multimap} in this > >> > multimap, > >> > > >> in > >> > > >>> the > >> > > >>> * order returned by {@code multimap.entries()}. > >> > > >>> * > >> > > >>> * @return {@code true} if the multimap changed > >> > > >>> */ > >> > > >>> public boolean putAll(IgniteMultimap<? extends K, ? extends > V> > >> > > >>> multimap); > >> > > >>> > >> > > >>> /** > >> > > >>> * Removes the key and all values associated with the key > >> {@code > >> > > >> key}. > >> > > >>> * > >> > > >>> * @return the list of values that were removed, or {@code > >> null} > >> > > >>> * if this map contains no mapping for the key. > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> */ > >> > > >>> public List<V> remove(K key); > >> > > >>> > >> > > >>> /** > >> > > >>> * Removes a single key-value pair with the key {@code key} > and > >> > the > >> > > >>> value > >> > > >>> * {@code value} from this multimap, if such exists. If > >> multiple > >> > > >>> key-value > >> > > >>> * pairs in the multimap fit this description, which one is > >> > removed > >> > > >> is > >> > > >>> * unspecified. > >> > > >>> * > >> > > >>> * @return {@code true} if the multimap changed > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> */ > >> > > >>> public boolean remove(K key, V value); > >> > > >>> > >> > > >>> /** > >> > > >>> * Stores a collection of values with the same key, replacing > >> any > >> > > >>> existing > >> > > >>> * values for that key. > >> > > >>> * > >> > > >>> * @return the collection of replaced values, or {@code null} > >> > > >>> * if this map contains no mapping for the key. > >> > > >>> * @throws ClassCastException if the key is of an > inappropriate > >> > > >>> type for this map > >> > > >>> */ > >> > > >>> List<V> replaceValues(K key, Iterable<? extends V> values); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns {@code true} if this map contains no key-value > >> > mappings. > >> > > >>> * > >> > > >>> * @return {@code true} if this map contains no key-value > >> mappings > >> > > >>> */ > >> > > >>> > >> > > >>> public boolean isEmpty(); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns the number of keys in this map. If the map > contains > >> > > >>> more than {@code Integer.MAX_VALUE} > >> > > >>> * elements, returns {@code Integer.MAX_VALUE}. > >> > > >>> * > >> > > >>> * @return the number of keys in this map > >> > > >>> */ > >> > > >>> public int size(); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns a list containing the <i>value</i> from each > >> key-value > >> > > >>> * pair contained in this multimap, without collapsing > >> duplicates. > >> > > >>> * > >> > > >>> * @return a list containing the <i>value</i> from each > >> key-value > >> > > >>> * pair contained in this multimap, without collapsing > >> duplicates. > >> > > >>> */ > >> > > >>> public List<V> values(); > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns the number of values that match the given key in > the > >> > > >>> multimap. > >> > > >>> * > >> > > >>> * @param key the key whose values count is to be returned > >> > > >>> * @return the number of values that match the given key in > the > >> > > >>> multimap > >> > > >>> */ > >> > > >>> public int valueCount(K key); > >> > > >>> > >> > > >>> /** > >> > > >>> * Gets multimap name. > >> > > >>> * > >> > > >>> * @return Multimap name. > >> > > >>> */ > >> > > >>> public String name(); > >> > > >>> > >> > > >>> /** > >> > > >>> * Removes this multimap. > >> > > >>> * > >> > > >>> * @throws IgniteException If operation failed. > >> > > >>> */ > >> > > >>> @Override public void close() throws IgniteException; > >> > > >>> > >> > > >>> /** > >> > > >>> * Returns {@code true} if this multimap can be kept on the > one > >> > node > >> > > >>> only. > >> > > >>> * Returns {@code false} if this multimap can be kept on the > >> many > >> > > >>> nodes. > >> > > >>> * > >> > > >>> * @return {@code true} if this multimap is in {@code > >> collocated} > >> > > >>> mode {@code false} otherwise. > >> > > >>> */ > >> > > >>> public boolean collocated(); > >> > > >>> > >> > > >>> /** > >> > > >>> * Executes given job on collocated multimap on the node > where > >> the > >> > > >>> multimap is located > >> > > >>> * (a.k.a. affinity co-location). > >> > > >>> * <p> > >> > > >>> * This is not supported for non-collocated multimaps. > >> > > >>> * > >> > > >>> * @param job Job which will be co-located with the multimap. > >> > > >>> * @throws IgniteException If job failed. > >> > > >>> */ > >> > > >>> public void affinityRun(IgniteRunnable job) throws > >> > IgniteException; > >> > > >>> > >> > > >>> /** > >> > > >>> * Executes given job on collocated multimap on the node > where > >> the > >> > > >>> multimap is located > >> > > >>> * (a.k.a. affinity co-location). > >> > > >>> * <p> > >> > > >>> * This is not supported for non-collocated multimaps. > >> > > >>> * > >> > > >>> * @param job Job which will be co-located with the multimap. > >> > > >>> * @throws IgniteException If job failed. > >> > > >>> */ > >> > > >>> public <R> R affinityCall(IgniteCallable<R> job) throws > >> > > >>> IgniteException; > >> > > >>> } > >> > > >>> > >> > > >>> > >> > > >>> > >> > > >>> -- > >> > > >>> Sincerely Yours Amir Akhmedov > >> > > >>> > >> > > >> > >> > > > >> > > > >> > > >> > > > > > -- > Sincerely Yours Amir Akhmedov >
