聊聊Elasticsearch的Iterables

28次阅读

共计 3988 个字符,预计需要花费 10 分钟才能阅读完成。

本文主要研究一下 Elasticsearch 的 Iterables

Iterables

elasticsearch-7.0.1/server/src/main/java/org/elasticsearch/common/util/iterable/Iterables.java

public class Iterables {public static <T> Iterable<T> concat(Iterable<T>... inputs) {Objects.requireNonNull(inputs);
        return new ConcatenatedIterable<>(inputs);
    }

    static class ConcatenatedIterable<T> implements Iterable<T> {private final Iterable<T>[] inputs;

        ConcatenatedIterable(Iterable<T>[] inputs) {this.inputs = Arrays.copyOf(inputs, inputs.length);
        }

        @Override
        public Iterator<T> iterator() {
            return Stream
                    .of(inputs)
                    .map(it -> StreamSupport.stream(it.spliterator(), false))
                    .reduce(Stream::concat)
                    .orElseGet(Stream::empty).iterator();}
    }

    /** Flattens the two level {@code Iterable} into a single {@code Iterable}.  Note that this pre-caches the values from the outer {@code
     *  Iterable}, but not the values from the inner one. */
    public static <T> Iterable<T> flatten(Iterable<? extends Iterable<T>> inputs) {Objects.requireNonNull(inputs);
        return new FlattenedIterables<>(inputs);
    }

    static class FlattenedIterables<T> implements Iterable<T> {
        private final Iterable<? extends Iterable<T>> inputs;

        FlattenedIterables(Iterable<? extends Iterable<T>> inputs) {List<Iterable<T>> list = new ArrayList<>();
            for (Iterable<T> iterable : inputs) {list.add(iterable);
            }
            this.inputs = list;
        }

        @Override
        public Iterator<T> iterator() {
            return StreamSupport
                    .stream(inputs.spliterator(), false)
                    .flatMap(s -> StreamSupport.stream(s.spliterator(), false)).iterator();}
    }

    public static <T> T get(Iterable<T> iterable, int position) {Objects.requireNonNull(iterable);
        if (position < 0) {throw new IllegalArgumentException("position >= 0");
        }
        if (iterable instanceof List) {List<T> list = (List<T>)iterable;
            if (position >= list.size()) {throw new IndexOutOfBoundsException(Integer.toString(position));
            }
            return list.get(position);
        } else {Iterator<T> it = iterable.iterator();
            for (int index = 0; index < position; index++) {if (!it.hasNext()) {throw new IndexOutOfBoundsException(Integer.toString(position));
                }
                it.next();}
            if (!it.hasNext()) {throw new IndexOutOfBoundsException(Integer.toString(position));
            }
            return it.next();}
    }
}
  • Iterables 提供了 concat、flatten、get 三个静态方法,其中 concat 返回的是 ConcatenatedIterable;flatten 返回的是 FlattenedIterables;get 方法会先判断是否是 List 类型是的话直接通过 position 取值返回,不是则遍历 iterable 获取指定 index 的元素

实例

elasticsearch-7.0.1/server/src/test/java/org/elasticsearch/common/util/iterable/IterablesTests.java

public class IterablesTests extends ESTestCase {public void testGetOverList() {test(Arrays.asList("a", "b", "c"));
    }

    public void testGetOverIterable() {Iterable<String> iterable = () ->
                new Iterator<String>() {
                    private int position = 0;

                    @Override
                    public boolean hasNext() {return position < 3;}

                    @Override
                    public String next() {if (position < 3) {
                            String s = position == 0 ? "a" : position == 1 ? "b" : "c";
                            position++;
                            return s;
                        } else {throw new NoSuchElementException();
                        }
                    }
                };
        test(iterable);
    }

    public void testFlatten() {List<List<Integer>> list = new ArrayList<>();
        list.add(new ArrayList<>());

        Iterable<Integer> allInts = Iterables.flatten(list);
        int count = 0;
        for(@SuppressWarnings("unused") int x : allInts) {count++;}
        assertEquals(0, count);
        list.add(new ArrayList<>());
        list.get(1).add(0);

        // changes to the outer list are not seen since flatten pre-caches outer list on init:
        count = 0;
        for(@SuppressWarnings("unused") int x : allInts) {count++;}
        assertEquals(0, count);

        // but changes to the original inner lists are seen:
        list.get(0).add(0);
        for(@SuppressWarnings("unused") int x : allInts) {count++;}
        assertEquals(1, count);
    }

    private void test(Iterable<String> iterable) {
        try {Iterables.get(iterable, -1);
            fail("expected IllegalArgumentException");
        } catch (IllegalArgumentException e) {assertThat(e, hasToString("java.lang.IllegalArgumentException: position >= 0"));
        }
        assertEquals("a", Iterables.get(iterable, 0));
        assertEquals("b", Iterables.get(iterable, 1));
        assertEquals("c", Iterables.get(iterable, 2));
        try {Iterables.get(iterable, 3);
            fail("expected IndexOutOfBoundsException");
        } catch (IndexOutOfBoundsException e) {assertThat(e, hasToString("java.lang.IndexOutOfBoundsException: 3"));
        }
    }
}
  • flatten 用于将 Iterable 类型的 Iterable 进行 flat 操作;get 方法则获取 iterable 中指定 index 的元素

小结

Iterables 提供了 concat、flatten、get 三个静态方法,其中 concat 返回的是 ConcatenatedIterable;flatten 返回的是 FlattenedIterables;get 方法会先判断是否是 List 类型是的话直接通过 position 取值返回,不是则遍历 iterable 获取指定 index 的元素

doc

  • Iterables

正文完
 0