LUCENE_7747: QueryBuilder now iterates lazily over the possible paths when building a graph query
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index bb2658a..234eb64 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -150,6 +150,8 @@
 * LUCENE-7695: ComplexPhraseQueryParser to support query time synonyms (Markus Jelsma
   via Mikhail Khludnev) 
 
+* LUCENE_7747: QueryBuilder now iterates lazily over the possible paths when building a graph query
+
 Optimizations
 
 * LUCENE-7641: Optimized point range queries to compute documents that do not
diff --git a/lucene/core/src/java/org/apache/lucene/util/QueryBuilder.java b/lucene/core/src/java/org/apache/lucene/util/QueryBuilder.java
index 286f673..fc5f97a 100644
--- a/lucene/core/src/java/org/apache/lucene/util/QueryBuilder.java
+++ b/lucene/core/src/java/org/apache/lucene/util/QueryBuilder.java
@@ -19,7 +19,6 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 
@@ -513,21 +512,20 @@
       lastState = end;
       final Query queryPos;
       if (graph.hasSidePath(start)) {
-        List<Query> queries = new ArrayList<> ();
-        Iterator<TokenStream> it = graph.getFiniteStrings(start, end);
-        while (it.hasNext()) {
-          TokenStream ts = it.next();
-          // This is a synonym path so all terms are mandatory (MUST).
-          Query q = createFieldQuery(ts, BooleanClause.Occur.MUST, field, getAutoGenerateMultiTermSynonymsPhraseQuery(), 0);
-          if (q != null) {
-            queries.add(q);
+        final Iterator<TokenStream> it = graph.getFiniteStrings(start, end);
+        Iterator<Query> queries = new Iterator<Query>() {
+          @Override
+          public boolean hasNext() {
+            return it.hasNext();
           }
-        }
-        if (queries.size() > 0) {
-          queryPos = newGraphSynonymQuery(queries.toArray(new Query[queries.size()]));
-        } else {
-          queryPos = null;
-        }
+
+          @Override
+          public Query next() {
+            TokenStream ts = it.next();
+            return createFieldQuery(ts, BooleanClause.Occur.MUST, field, getAutoGenerateMultiTermSynonymsPhraseQuery(), 0);
+          }
+        };
+        queryPos = newGraphSynonymQuery(queries);
       } else {
         Term[] terms = graph.getTerms(field, start);
         assert terms.length > 0;
@@ -637,16 +635,16 @@
    * This is intended for subclasses that wish to customize the generated queries.
    * @return new Query instance
    */
-  protected Query newGraphSynonymQuery(Query queries[]) {
-    if (queries == null) {
-      return new BooleanQuery.Builder().build();
-    } else if (queries.length == 1) {
-      return queries[0];
-    } else {
-      BooleanQuery.Builder builder = new BooleanQuery.Builder();
-      Arrays.stream(queries).forEachOrdered(qry -> builder.add(qry, BooleanClause.Occur.SHOULD));
-      return builder.build();
+  protected Query newGraphSynonymQuery(Iterator<Query> queries) {
+    BooleanQuery.Builder builder = new BooleanQuery.Builder();
+    while (queries.hasNext()) {
+      builder.add(queries.next(), BooleanClause.Occur.SHOULD);
     }
+    BooleanQuery bq = builder.build();
+    if (bq.clauses().size() == 1) {
+      return bq.clauses().get(0).getQuery();
+    }
+    return bq;
   }
   
   /**