Дубликат ключа в кэше гуавы - PullRequest
0 голосов
/ 14 марта 2019

Я реализовал этот кеш Guava в 1 из моего сервиса SpringBoot:

public class CachedMenuServiceImpl implements MenuService {

        private  LoadingCache<String, MenuChart2> menuChartCache = CacheBuilder.newBuilder()
                .maximumSize(15)
                .expireAfterAccess(15, TimeUnit.MINUTES)
                .build(
                        new CacheLoader<String, MenuChart2>() {
                            public MenuChart2 load(String menuSymbol) throws ExecutionException {
                                   return generateCharts (menuSymbol);    
                            }
                        }
                );



    @Override
    public MenuChart2 getCharts (String menuSymbol) throws ExecutionException {

        return menuChartCache.get(menuSymbol);      
    }


public MenuChart2 generateCharts (String MenuSymbol) throws ExecutionException {

        MenuChart2 menuChart2;

       …
       return menuChart2;
}


public MenuChart2 generateCharts (String menuSymbol) throws ExecutionException {


        if (LOG.isDebugEnabled()) {
            LOG.debug ("generating charts for {} ", menuSymbol);
        }

        Menu menu = findBySymbol(menuSymbol).get();

        Map<LocalDate, MenuChart2.Statistics> last30DPerDay =   

                menuPriceByDayService.findAllOrderByUpdateDate(menu, DateUtils.monthlyDate(), 30)
                .stream()
                .sorted(comparing(MenuPriceByDay::getUpdateDate))
                .collect(Collectors
                        .toMap(MenuPriceByDay::getUpdateLocalDate, p -> new MenuChart2().new Statistics( p.getMinPrice().doubleValue(), 
                                                                                                                            p.getMaxPrice().doubleValue(),
                                                                                                                            p.getAvgPrice().doubleValue())));

            Map<LocalDate, MenuChart2.Statistics> last3MPerDay =    

                    menuPriceByDayService.findAllOrderByUpdateDate(menu, DateUtils.quarterlyDate(), 92)
                    .stream()
                    .sorted(comparing(MenuPriceByDay::getUpdateDate))
                    .collect(Collectors
                            .toMap(MenuPriceByDay::getUpdateLocalDate, p -> new MenuChart2().new Statistics( p.getMinPrice().doubleValue(), 
                                                                                                                                p.getMaxPrice().doubleValue(),
                                                                                                                                p.getAvg;

            Map<LocalDate, MenuChart2.Statistics> last6MPerDay =    

                    menuPriceByDayService.findAllOrderByUpdateDate(menu, DateUtils.semestralDate(), 26)
                    .stream()
                    .sorted(comparing(MenuPriceByDay::getUpdateDate))
                    .collect(Collectors
                            .toMap(MenuPriceByDay::getUpdateLocalDate, p -> new MenuChart2().new Statistics( p.getMinPrice().doubleValue(), 
                                                                                                                                p.getMaxPrice().doubleValue(),
                                                                                                                                p.getAvgPrice().doubleValue())));

            Map<LocalDate, MenuChart2.Statistics> last1YPerDay =    

                    menuPriceByDayService.findAllOrderByUpdateDate(menu, DateUtils.yearlylDate(), 52)
                    .stream()
                    .sorted(comparing(MenuPriceByDay::getUpdateDate))
                    .collect(Collectors
                            .toMap(MenuPriceByDay::getUpdateLocalDate, p -> new MenuChart2().new Statistics( p.getMinPrice().doubleValue(), 
                                                                                                                                p.getMaxPrice().doubleValue(),
                                                                                                                                p.getAvgPrice().doubleValue())));


            Map<LocalDateTime, DoubleSummaryStatistics> priceStatisticsXhour =

                    menuPriceService.findAll(menu).parallelStream()
                            .filter(cp -> cp.getUpdateDate().after(DateUtils.yesterday()))
                            .sorted(comparing(MenuPrice::getUpdateDate))
                            .collect(Collectors.groupingBy(cp -> cp.getUpdateLocalDateHour(),
                                    Collectors.summarizingDouble(cp -> cp.getPriceInDouble())))
                            .entrySet().parallelStream().sorted(Map.Entry.comparingByKey())
                            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                                    (oldValue, newValue) -> oldValue, LinkedHashMap::new));


            MenuChart2 menuChart2 = new MenuChart2();

            menuChart2.setLas24HPerHour (priceStatisticsXhour);
            menuChart2.setLast30DPerDay (last30DPerDay);
            menuChart2.setLast1YPerDay  (last1YPerDay);
            menuChart2.setLast3MPerDay  (last3MPerDay);
            menuChart2.setLast6MPerDay  (last6MPerDay);

            return menuChart2;

    }

, но когда я получил к нему доступ, я получил эту ошибку:

com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalStateException: Duplicate key com.tdk.api.json.MenuChart2$Statistics@6f377595
    at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2218)
    at com.google.common.cache.LocalCache.get(LocalCache.java:4147)
    at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:4151)
    at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:5140)
    at com.tdk.backend.service.CachedMenuServiceImpl.getCharts(CachedMenuServiceImpl.java:189)
    at com.tdk.backend.service.CachedMenuServiceImpl$$FastClassBySpringCGLIB$$2ea84be7.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)

...

Caused by: java.lang.IllegalStateException: Duplicate key com.tdk.api.json.MenuChart2$Statistics@6f377595
    at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
    at java.util.HashMap.merge(HashMap.java:1254)
    at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
    at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
    at java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:352)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
    at com.tdk.backend.service.CachedMenuServiceImpl.generateCharts(CachedMenuServiceImpl.java:238)
    at com.tdk.backend.service.CachedMenuServiceImpl$1.load(CachedMenuServiceImpl.java:86)
    at com.tdk.backend.service.CachedMenuServiceImpl$1.load(CachedMenuServiceImpl.java:84)
    at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3708)
    at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2416)
    at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2299)
    at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2212)
    ... 101 common frames omitted

1 Ответ

0 голосов
/ 15 марта 2019

Исключение не поступает из кэша Гуавы. Похоже, что он исходит от вас, используя поток и собирая его в карту. Исключение возникает при вызове .get(..), потому что это LoadingCache, поэтому при запуске кода в методе генерации генерируется исключение. Вы, вероятно, делаете что-то вроде

.stream().collect(
                Collectors.toMap(o -> someFunctionToGetKey(),
                                 o -> someFunctionToGetValue())
        );

Однако в этой реализации вы не предоставляете логику того, что должно произойти, если генерируются два одинаковых ключа. Вам нужно указать третий параметр, который определяет поведение при обнаружении дубликата ключа. Например, предположим, что у нас есть это основное pojo

@Data
class Model {
    private int id;
    private String name;
}

А у нас List<Model> list = new ArrayList<>();

Затем вы можете сделать:

                list.stream()
                .collect(Collectors.toMap(
                        Model::getId,
                        Model::getName,
                        (v1,v2) -> v2
                ));

Третий параметр, (v2,v2) -> v2, указывает сборщику, что делать, если в списке есть две записи с одинаковым идентификатором. В этом примере он просто использует самое последнее значение name для ключа id.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...