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 > > > >>> > > > >> > > > > > > > > >
