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
