Поддержание нескольких индексов с кешем guava (в памяти)
Я пытаюсь реализовать упрощенную в кэше "таблицу" в памяти, где есть 2 типа индексов: первичный и вторичный.
Очень похож на таблицу в мире РСУБД, где есть несколько столбцов поиска. Иногда вы хотите искать по PK, иногда возвращаете список строк на основе общего свойства. Прямо сейчас нет необходимости в других операциях, чем equals (=) (т.е. Без запросов диапазона или сопоставления с образцом).
Добавить семантику кэша в указанную выше структуру данных (выселение, загрузку данных/загрузчик кэша, обновление и т.д.) и что в значительной степени необходимо.
Я хотел бы попросить ваш совет о том, как наилучшим образом подойти к данной проблеме. Должен ли он быть кешем на индекс или кеш (для ПК) + (синхронизированный) Multimap для вторичных индексов?
Любая помощь очень ценится.
С уважением.
Ответы
Ответ 1
Вы можете заменить карту на Guava com.google.common.cache.Cache. Он не поддерживает семантику типа Multimap, поэтому вам придется использовать
Cache<K, ? extends List<V>>
в этом случае.
Для простоты я сделаю "основной индекс" подмножеством вторичного индекса - т.е. у вас есть один индекс, который возвращает список значений для данного ключа, а первичные ключи просто возвращают список с одним значением,
Ответ 2
Задача состоит в том, чтобы поддерживать целостность двух индексов независимо от того, используете ли вы два кеша или даже один кэш для PK + multimap.
Возможно, вам следует создать новый класс кеша (скажем, TableCache), который расширяет com.google.common.cache.Cache, внутри этого класса может поддерживать переменную экземпляра мультимапа для вторичного индекса (который может быть ConcurrentHashMap).
Затем вы можете переопределить методы кэша (put, get, invalidate и т.д.), чтобы синхронизировать вторичный индекс.
Конечно, вы должны предоставить функцию get для извлечения значений на основе вторичного индекса.
Этот подход дает вам возможность поддерживать целостность первичных и вторичных индексов.
public class TableCache<K, V> extends Cache<K, V> {
Map<K, List<V>> secondaryIndex = new ConcurrentHashMap<K, List<V>>();
public void put(K key, V value) {
super.put(key, value);
// Update secondaryIndex
}
}
Ответ 3
У меня была эта проблема много раз.
Что бы исправить эту проблему, если Java лучше поддержка STM. Очень сложно создавать неблокирующие структуры атомных данных. Лучшее, что я видел, это multiverse.
Таким образом, ответ @vladimir, вероятно, лучший, но я бы сказал, что хранящиеся коллекции должны быть неизменными, и вам придется извлекать всю коллекцию при обновлении/кеше и т.д. Также, если вы измените один из членов multiset, у вас будет трудное время, зная, как обновить его родительский элемент и аннулировать кеш.
В противном случае я бы рассмотрел что-то вроде Redis для больших наборов данных, которое поддерживает атомные операции над картами и комбинациями списков.