Java 8 Una corriente de hacer corresponder múltiples

Yilmaz:

Digamos que tengo enorme archivo de registro del servidor web que no encaja en la memoria. Necesito para transmitir este archivo a un método mapreduce y guardar en la base de datos. Lo hago uso de Java 8 api corriente. Por ejemplo, puedo obtener una lista después del proceso de mapreduce tales como, el consumo por el cliente, el consumo a través de IP, el consumo de los contenidos. Pero, mis necesidades no son que al igual que dado en mi ejemplo. Ya que no puedo compartir el código, sólo quiero dar ejemplo básico.

Por Java 8 Corriente del Api, quiero leer el archivo exactamente una vez, obtener 3 listas al mismo tiempo, mientras yo estoy Transmisión de archivos, paralelo o secuencial. Pero en paralelo sería bueno. ¿Hay alguna forma de hacer eso?

Malte Hartwig:

He adaptado la respuesta a esta pregunta a su caso. El Spliterator personalizada va a "dividir" la corriente en múltiples flujos que recogen por diferentes propiedades:

@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;
        }
    }
}

Se puede utilizar de la siguiente manera:

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

Observe que puede hacer casi cualquier cosa que quiera con sus copias de la corriente. Como por su ejemplo, he usado un apilado groupingBycolector para agrupar las filas por dos propiedades y luego resumió la propiedad int. Así, el resultado será una Map<String, Map<String, Integer>>. Pero también se puede utilizar para otros escenarios:

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

Supongo que te gusta

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