package edu.stanford.nlp.sempre.tables.serialize; import java.io.File; import java.util.*; import java.util.regex.Matcher; import edu.stanford.nlp.sempre.*; import fig.basic.*; /** * Lazily read and construct examples from a dump file. * * The process is fast if the examples are read sequentially. * * @author ppasupat */ public class LazyLoadedExampleList implements List<Example> { public static class Options { @Option(gloss = "whether to ensure thread safety (makes things slower)") public boolean threadSafe = false; } public static Options opts = new Options(); private final List<String> paths; private final List<Integer> sizes; private final List<Integer> offsets; private final List<Integer> exampleIndexToPathIndex; private final int size; // Whether each file contains only a single example (faster) private final boolean single; private LazyLoadedExampleListIterator defaultIterator; public LazyLoadedExampleList(String path, int maxSize) { this(Collections.singletonList(path), maxSize); } public LazyLoadedExampleList(List<String> paths, int maxSize) { this(paths, maxSize, false); } public LazyLoadedExampleList(List<String> paths, int maxSize, boolean single) { this.paths = new ArrayList<>(paths); this.single = single; // Combined the number of examples from all files this.sizes = new ArrayList<>(); this.offsets = new ArrayList<>(); this.exampleIndexToPathIndex = new ArrayList<>(); int size = 0; for (int pathIndex = 0; pathIndex < paths.size(); pathIndex++) { String path = paths.get(pathIndex); if (single) { sizes.add(1); exampleIndexToPathIndex.add(pathIndex); offsets.add(size); size++; } else { int thisSize = readSizeFromMetadata(LispTree.proto.parseFromFile(path).next()); sizes.add(thisSize); for (int i = 0; i < thisSize; i++) exampleIndexToPathIndex.add(pathIndex); offsets.add(size); size += thisSize; } } this.size = Math.min(size, maxSize); LogInfo.logs("(LazyLoadedExampleList) Dataset size: %d", this.size); defaultIterator = new LazyLoadedExampleListIterator(); } public List<String> getPaths() { return paths; } @Override public int size() { return size; } @Override public boolean isEmpty() { return size == 0; } // ============================================================ // Iterator // ============================================================ public class LazyLoadedExampleListIterator implements Iterator<Example> { Iterator<LispTree> trees = null; private int currentPathIndex = -1, currentIndex = -1; private Example currentExample = null; @Override public boolean hasNext() { return currentIndex + 1 < size; // size could be affected by MaxExampleForGroup } @Override public Example next() { currentIndex++; while (trees == null || !trees.hasNext()) { trees = LispTree.proto.parseFromFile(paths.get(++currentPathIndex)); trees.next(); // Skip metadata } return currentExample = readExample(trees.next()); } public Example seek(int index) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException("Array size: " + size + "; No index " + index); int pathIndex = exampleIndexToPathIndex.get(index); if (pathIndex != currentPathIndex || currentIndex > index) { currentPathIndex = pathIndex; trees = LispTree.proto.parseFromFile(paths.get(currentPathIndex)); trees.next(); // Skip metadata currentIndex = offsets.get(pathIndex) - 1; } while (currentIndex < index) { currentIndex++; LispTree tree = trees.next(); if (currentIndex == index) currentExample = readExample(tree); } return currentExample; } public int getCurrentIndex() { return currentIndex; } public Example getCurrentExample() { return currentExample; } } @Override public Iterator<Example> iterator() { return new LazyLoadedExampleListIterator(); } @Override public Example get(int index) { if (opts.threadSafe) return new LazyLoadedExampleListIterator().seek(index); return defaultIterator.seek(index); } public List<Example> loadAll() { List<Example> examples = new ArrayList<>(); Iterator<Example> itr = iterator(); while (itr.hasNext()) examples.add(itr.next()); return examples; } public List<String> getAllIds() { List<String> ids = new ArrayList<>(); for (String path : paths) { if (single) { Matcher matcher = SerializedDataset.GZ_PATTERN.matcher(new File(path).getName()); matcher.matches(); ids.add(matcher.group(3)); } else { Iterator<LispTree> trees = LispTree.proto.parseFromFile(path); while (trees.hasNext()) { LispTree tree = trees.next(); String exampleId = getExampleId(tree); if (exampleId != null) ids.add(exampleId); } } } return ids; } // ============================================================ // Read Metadata // ============================================================ private int readSizeFromMetadata(LispTree tree) { if (!"metadata".equals(tree.child(0).value)) throw new RuntimeException("Not metadata: " + tree); for (int i = 1; i < tree.children.size(); i++) { LispTree arg = tree.child(i); if ("size".equals(arg.child(0).value)) return Integer.parseInt(arg.child(1).value); } throw new RuntimeException("Size not specified: " + tree); } // ============================================================ // LispTree --> Example // ============================================================ private static final Set<String> finalFields = new HashSet<>(Arrays.asList( "id", "utterance", "targetFormula", "targetValue", "targetValues", "context")); private String getExampleId(LispTree tree) { if (!"example".equals(tree.child(0).value)) return null; for (int i = 1; i < tree.children.size(); i++) { LispTree arg = tree.child(i); if ("id".equals(arg.child(0).value)) { return arg.child(1).value; } } // The ID is missing. Throw an error. String treeS = tree.toString(); treeS = treeS.substring(0, Math.min(140, treeS.length())); throw new RuntimeException("Example does not have an ID: " + treeS); } private Example readExample(LispTree tree) { Example.Builder b = new Example.Builder(); if (!"example".equals(tree.child(0).value)) LogInfo.fails("Not an example: %s", tree); // final fields for (int i = 1; i < tree.children.size(); i++) { LispTree arg = tree.child(i); String label = arg.child(0).value; if ("id".equals(label)) { b.setId(arg.child(1).value); } else if ("utterance".equals(label)) { b.setUtterance(arg.child(1).value); } else if ("targetFormula".equals(label)) { b.setTargetFormula(Formulas.fromLispTree(arg.child(1))); } else if ("targetValue".equals(label) || "targetValues".equals(label)) { if (arg.children.size() != 2) throw new RuntimeException("Expect one target value"); b.setTargetValue(Values.fromLispTree(arg.child(1))); } else if ("context".equals(label)) { b.setContext(new ContextValue(arg)); } } b.setLanguageInfo(new LanguageInfo()); Example ex = b.createExample(); // other fields for (int i = 1; i < tree.children.size(); i++) { LispTree arg = tree.child(i); String label = arg.child(0).value; if ("tokens".equals(label)) { int n = arg.child(1).children.size(); for (int j = 0; j < n; j++) ex.languageInfo.tokens.add(arg.child(1).child(j).value); } else if ("lemmaTokens".equals(label)) { int n = arg.child(1).children.size(); for (int j = 0; j < n; j++) ex.languageInfo.lemmaTokens.add(arg.child(1).child(j).value); } else if ("posTags".equals(label)) { int n = arg.child(1).children.size(); for (int j = 0; j < n; j++) ex.languageInfo.posTags.add(arg.child(1).child(j).value); } else if ("nerTags".equals(label)) { int n = arg.child(1).children.size(); for (int j = 0; j < n; j++) ex.languageInfo.nerTags.add(arg.child(1).child(j).value); } else if ("nerValues".equals(label)) { int n = arg.child(1).children.size(); for (int j = 0; j < n; j++) { String value = arg.child(1).child(j).value; if ("null".equals(value)) value = null; ex.languageInfo.nerValues.add(value); } } else if ("derivations".equals(label)) { ex.predDerivations = new ArrayList<>(); for (int j = 1; j < arg.children.size(); j++) ex.predDerivations.add(readDerivation(arg.child(j))); } else if (!finalFields.contains(label)) { throw new RuntimeException("Invalid example argument: " + arg); } } return ex; } public static final String SERIALIZED_ROOT = "$SERIALIZED_ROOT"; private Derivation readDerivation(LispTree tree) { Derivation.Builder b = new Derivation.Builder() .cat(SERIALIZED_ROOT).start(-1).end(-1).localFeatureVector(new FeatureVector()) .rule(Rule.nullRule).children(new ArrayList<Derivation>()); if (!"derivation".equals(tree.child(0).value)) LogInfo.fails("Not a derivation: %s", tree); for (int i = 1; i < tree.children.size(); i++) { LispTree arg = tree.child(i); String label = arg.child(0).value; if ("formula".equals(label)) { b.formula(Formulas.fromLispTree(arg.child(1))); } else if ("type".equals(label)) { b.type(SemType.fromLispTree(arg.child(1))); } else if ("value".equals(label)) { b.value(Values.fromLispTree(arg.child(1))); } else if (label.endsWith("values")) { List<Value> values = new ArrayList<>(); for (int j = 1; j < arg.children.size(); j++) { values.add(Values.fromLispTree(arg.child(j))); } b.value(new ListValue(values)); } else if ("canonicalUtterance".equals(label)) { b.canonicalUtterance(arg.child(1).value); } else { throw new RuntimeException("Invalid derivation argument: " + arg); } } return b.createDerivation(); } // ============================================================ // Unimplemented methods // ============================================================ @Override public boolean contains(Object o) { throw new RuntimeException("Not implemented!"); } @Override public Object[] toArray() { throw new RuntimeException("Not implemented!"); } @Override public <T> T[] toArray(T[] a) { throw new RuntimeException("Not implemented!"); } @Override public boolean add(Example e) { throw new RuntimeException("Not implemented!"); } @Override public boolean remove(Object o) { throw new RuntimeException("Not implemented!"); } @Override public boolean containsAll(Collection<?> c) { throw new RuntimeException("Not implemented!"); } @Override public boolean addAll(Collection<? extends Example> c) { throw new RuntimeException("Not implemented!"); } @Override public boolean addAll(int index, Collection<? extends Example> c) { throw new RuntimeException("Not implemented!"); } @Override public boolean removeAll(Collection<?> c) { throw new RuntimeException("Not implemented!"); } @Override public boolean retainAll(Collection<?> c) { throw new RuntimeException("Not implemented!"); } @Override public void clear() { throw new RuntimeException("Not implemented!"); } @Override public Example set(int index, Example element) { throw new RuntimeException("Not implemented!"); } @Override public void add(int index, Example element) { throw new RuntimeException("Not implemented!"); } @Override public Example remove(int index) { throw new RuntimeException("Not implemented!"); } @Override public int indexOf(Object o) { throw new RuntimeException("Not implemented!"); } @Override public int lastIndexOf(Object o) { throw new RuntimeException("Not implemented!"); } @Override public ListIterator<Example> listIterator() { throw new RuntimeException("Not implemented!"); } @Override public ListIterator<Example> listIterator(int index) { throw new RuntimeException("Not implemented!"); } @Override public List<Example> subList(int fromIndex, int toIndex) { throw new RuntimeException("Not implemented!"); } }