Java 8 um fluxo para Multiple Mapa

Yilmaz:

Vamos dizer que tenho enorme arquivo de log do servidor web que não se encaixa na memória. Eu preciso para transmitir esse arquivo para um método mapreduce e salvar a base de dados. Eu faço isso usando Java 8 fluxo de api. Por exemplo, posso obter uma lista após o processo de mapreduce tais como, o consumo por cliente, o consumo por ip, o consumo por conteúdo. Mas, minhas necessidades não são como aquele dado no meu exemplo. Já que não posso compartilhar código, eu só quero dar exemplo básico.

Por Java 8 Fluxo Api, eu quero ler o arquivo exatamente uma vez, obter 3 listas ao mesmo tempo, enquanto eu estou streaming de arquivos, paralelo ou sequencial. Mas paralela seria bom. Existe alguma maneira de fazer isso?

Malte Hartwig:

I se adaptaram a resposta a esta pergunta ao seu caso. O Spliterator costume vai "dividir" o fluxo em múltiplos fluxos que recolhem por propriedades diferentes:

@SafeVarargs
public static <T> long streamForked(Stream<T> source, Consumer<Stream<T>>... consumers)
{
    return StreamSupport.stream(new ForkingSpliterator<>(source, consumers), false).count();
}

public static class ForkingSpliterator<T>
    extends AbstractSpliterator<T>
{
    private Spliterator<T>         sourceSpliterator;

    private List<BlockingQueue<T>> queues = new ArrayList<>();

    private boolean                sourceDone;

    @SafeVarargs
    private ForkingSpliterator(Stream<T> source, Consumer<Stream<T>>... consumers)
    {
        super(Long.MAX_VALUE, 0);

        sourceSpliterator = source.spliterator();

        for (Consumer<Stream<T>> fork : consumers)
        {
            LinkedBlockingQueue<T> queue = new LinkedBlockingQueue<>();
            queues.add(queue);
            new Thread(() -> fork.accept(StreamSupport.stream(new ForkedConsumer(queue), false))).start();
        }
    }

    @Override
    public boolean tryAdvance(Consumer<? super T> action)
    {
        sourceDone = !sourceSpliterator.tryAdvance(t -> queues.forEach(queue -> queue.offer(t)));
        return !sourceDone;
    }

    private class ForkedConsumer
        extends AbstractSpliterator<T>
    {
        private BlockingQueue<T> queue;

        private ForkedConsumer(BlockingQueue<T> queue)
        {
            super(Long.MAX_VALUE, 0);
            this.queue = queue;
        }

        @Override
        public boolean tryAdvance(Consumer<? super T> action)
        {
            while (queue.peek() == null)
            {
                if (sourceDone)
                {
                    // element is null, and there won't be no more, so "terminate" this sub stream
                    return false;
                }
            }

            // push to consumer pipeline
            action.accept(queue.poll());

            return true;
        }
    }
}

Você pode usá-lo da seguinte forma:

streamForked(Stream.of(new Row("content1", "client1", "location1", 1),
                       new Row("content2", "client1", "location1", 2),
                       new Row("content1", "client1", "location2", 3),
                       new Row("content2", "client2", "location2", 4),
                       new Row("content1", "client2", "location2", 5)),
             rows -> System.out.println(rows.collect(Collectors.groupingBy(Row::getClient,
                                                                           Collectors.groupingBy(Row::getContent,
                                                                                                 Collectors.summingInt(Row::getConsumption))))),
             rows -> System.out.println(rows.collect(Collectors.groupingBy(Row::getClient,
                                                                           Collectors.groupingBy(Row::getLocation,
                                                                                                 Collectors.summingInt(Row::getConsumption))))),
             rows -> System.out.println(rows.collect(Collectors.groupingBy(Row::getContent,
                                                                           Collectors.groupingBy(Row::getLocation,
                                                                                                 Collectors.summingInt(Row::getConsumption))))));

// Output
// {client2={location2=9}, client1={location1=3, location2=3}}
// {client2={content2=4, content1=5}, client1={content2=2, content1=4}}
// {content2={location1=2, location2=4}, content1={location1=1, location2=8}}

Note que você pode fazer praticamente qualquer coisa que quiser com seus as cópias do fluxo. Como por seu exemplo, eu usei um empilhados groupingBycoletor para agrupar as linhas por duas propriedades e, em seguida, resumiu a propriedade int. Assim, o resultado será um Map<String, Map<String, Integer>>. Mas você também pode usá-lo para outros cenários:

rows -> System.out.println(rows.count())
rows -> rows.forEach(row -> System.out.println(row))
rows -> System.out.println(rows.anyMatch(row -> row.getConsumption() > 3))

Acho que você gosta

Origin http://43.154.161.224:23101/article/api/json?id=177341&siteId=1
Recomendado
Clasificación