You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2020/06/04 15:10:21 UTC

[lucene-solr] 01/01: SOLR-14470: More cleanups, tighter access to Tuple internals.

This is an automated email from the ASF dual-hosted git repository.

ab pushed a commit to branch jira/solr-14470-2
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit 56ec96538f165694f896a6ff994899923d749694
Author: Andrzej Bialecki <ab...@apache.org>
AuthorDate: Thu Jun 4 17:09:40 2020 +0200

    SOLR-14470: More cleanups, tighter access to Tuple internals.
---
 .../org/apache/solr/handler/ExportHandler.java     |  6 +-
 .../java/org/apache/solr/handler/GraphHandler.java |  2 +-
 .../org/apache/solr/handler/StreamHandler.java     |  2 +-
 .../apache/solr/handler/export/ExportWriter.java   | 12 ----
 .../solr/response/GraphMLResponseWriter.java       |  2 +-
 solr/solr-ref-guide/src/exporting-result-sets.adoc | 28 ++++++++++
 .../org/apache/solr/client/solrj/io/Tuple.java     | 64 ++++++++++++++++++++--
 .../client/solrj/io/eval/RecursiveEvaluator.java   |  4 +-
 .../client/solrj/io/eval/SetValueEvaluator.java    |  2 +-
 .../solr/client/solrj/io/ops/GroupOperation.java   |  2 +-
 .../solr/client/solrj/io/stream/CommitStream.java  |  2 +-
 .../solr/client/solrj/io/stream/DaemonStream.java  |  2 +-
 .../solr/client/solrj/io/stream/GetStream.java     |  2 +-
 .../solr/client/solrj/io/stream/PlotStream.java    |  4 +-
 .../solr/client/solrj/io/stream/RollupStream.java  |  9 +--
 .../client/solrj/io/stream/ScoreNodesStream.java   |  4 +-
 .../solr/client/solrj/io/stream/SelectStream.java  |  2 +-
 .../solr/client/solrj/io/stream/TupStream.java     |  4 +-
 .../solr/client/solrj/io/stream/UpdateStream.java  |  4 +-
 .../solr/client/solrj/io/stream/ZplotStream.java   | 11 ++--
 .../solrj/io/stream/CloudAuthStreamTest.java       |  4 +-
 .../client/solrj/io/stream/JDBCStreamTest.java     |  4 +-
 .../solrj/io/stream/SelectWithEvaluatorsTest.java  |  4 +-
 .../solrj/io/stream/StreamDecoratorTest.java       |  6 +-
 .../solrj/io/stream/StreamExpressionTest.java      |  4 +-
 25 files changed, 124 insertions(+), 66 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/handler/ExportHandler.java b/solr/core/src/java/org/apache/solr/handler/ExportHandler.java
index e897c65..04800a3 100644
--- a/solr/core/src/java/org/apache/solr/handler/ExportHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/ExportHandler.java
@@ -58,7 +58,7 @@ public class ExportHandler extends SearchHandler {
         "commit", "random", "knnSearch",
         // execution streams
         "parallel", "executor", "daemon"
-        // nocommit other streams?
+        // other streams?
     };
 
     public ExportHandlerStreamFactory() {
@@ -99,10 +99,6 @@ public class ExportHandler extends SearchHandler {
     initialStreamContext.put("solr-core", core);
   }
 
-  public StreamContext getInitialStreamContext() {
-    return initialStreamContext;
-  }
-
   @Override
   public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
     try {
diff --git a/solr/core/src/java/org/apache/solr/handler/GraphHandler.java b/solr/core/src/java/org/apache/solr/handler/GraphHandler.java
index 42e8985..a3a5cfa 100644
--- a/solr/core/src/java/org/apache/solr/handler/GraphHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/GraphHandler.java
@@ -253,7 +253,7 @@ public class GraphHandler extends RequestHandlerBase implements SolrCoreAware, P
       Tuple tuple = this.tupleStream.read();
       if(tuple.EOF) {
         long totalTime = (System.nanoTime() - begin) / 1000000;
-        tuple.fields.put(StreamParams.RESPONSE_TIME, totalTime);
+        tuple.put(StreamParams.RESPONSE_TIME, totalTime);
       }
       return tuple;
     }
diff --git a/solr/core/src/java/org/apache/solr/handler/StreamHandler.java b/solr/core/src/java/org/apache/solr/handler/StreamHandler.java
index 81fc9fb..2fa8f61 100644
--- a/solr/core/src/java/org/apache/solr/handler/StreamHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/StreamHandler.java
@@ -481,7 +481,7 @@ public class StreamHandler extends RequestHandlerBase implements SolrCoreAware,
       Tuple tuple = this.tupleStream.read();
       if (tuple.EOF) {
         long totalTime = (System.nanoTime() - begin) / 1000000;
-        tuple.fields.put(StreamParams.RESPONSE_TIME, totalTime);
+        tuple.put(StreamParams.RESPONSE_TIME, totalTime);
       }
       return tuple;
     }
diff --git a/solr/core/src/java/org/apache/solr/handler/export/ExportWriter.java b/solr/core/src/java/org/apache/solr/handler/export/ExportWriter.java
index ea6e57d..1cc5f5b 100644
--- a/solr/core/src/java/org/apache/solr/handler/export/ExportWriter.java
+++ b/solr/core/src/java/org/apache/solr/handler/export/ExportWriter.java
@@ -392,7 +392,6 @@ public class ExportWriter implements SolrCore.RawWriter, Closeable {
       }
       streamContext = new StreamContext();
       streamContext.setRequestParams(params);
-      // nocommit enforce this?
       streamContext.setLocal(true);
 
       streamContext.workerID = 0;
@@ -517,17 +516,6 @@ public class ExportWriter implements SolrCore.RawWriter, Closeable {
         addDocsToItemWriter(leaves, writer, outDocs, outDocsIndex);
       }
     }
-    // nocommit clean it up
-    if (sortDoc != null) {
-      for (SortValue sv : sortDoc.getSortValues()) {
-        if (sv instanceof StringValue) {
-          StringValue stringValue = (StringValue) sv;
-          log.info(" - " + stringValue.field + ": cacheHit=" + stringValue.cacheHit +
-              ", cacheMiss=" + stringValue.cacheMiss + ", cacheEvict=" + stringValue.cacheEvict +
-              ", cacheClear=" + stringValue.cacheClear);
-        }
-      }
-    }
   }
 
   private int fillOutDocs(List<LeafReaderContext> leaves, SortDoc sortDoc,
diff --git a/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java b/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java
index 85346be..926d79f 100644
--- a/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java
+++ b/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java
@@ -95,7 +95,7 @@ public class GraphMLResponseWriter implements QueryResponseWriter {
         printWriter.write("<node id=\""+ xmlEscape(id)+"\"");
 
         List<String> outfields = new ArrayList();
-        Iterator<Object> keys = tuple.fields.keySet().iterator();
+        Iterator<Object> keys = tuple.getFields().keySet().iterator();
         while(keys.hasNext()) {
           String key = String.valueOf(keys.next());
           if(key.equals("node") || key.equals("ancestors") || key.equals("collection")) {
diff --git a/solr/solr-ref-guide/src/exporting-result-sets.adoc b/solr/solr-ref-guide/src/exporting-result-sets.adoc
index b0565d8..e28928b 100644
--- a/solr/solr-ref-guide/src/exporting-result-sets.adoc
+++ b/solr/solr-ref-guide/src/exporting-result-sets.adoc
@@ -59,6 +59,34 @@ It can get worse otherwise.
 
 The `fl` property defines the fields that will be exported with the result set. Any of the field types that can be sorted (i.e., int, long, float, double, string, date, boolean) can be used in the field list. The fields can be single or multi-valued. However, returning scores and wildcards are not supported at this time.
 
+=== Specifying the Local Streaming Expression
+
+The optional `expr` property defines a <<streaming-expressions.adoc#streaming-expressions,stream expression>> that allows documents to be processed locally before they are exported in the result set.
+
+Expressions have to use a special `input()` stream that represents original results from the `/export` handler. Output from the stream expression then becomes the output from the `/export` handler. The `&streamLocalOnly=true` flag is always set for this streaming expression.
+
+Only stream <<streaming-expressions.adoc#stream-decorator-reference,decorators>> and <<streaming-expressions.adoc#stream-evaluator-reference,evaluators>> are supported in these expressions - using any of the <<streaming-expressions.adoc#stream-source-reference,source>> expressions except for the pre-defined `input()` will result in an error.
+
+Using stream expressions with the `/export` handler may result in dramatic performance improvements due to the local in-memory reduction of the number of documents to be returned.
+
+Here's an example of using `top` decorator for returning only top N results:
+[source,text]
+----
+http://localhost:8983/solr/core_name/export?q=my-query&sort=timestamp+desc,&fl=timestamp,reporter,severity&expr=top(n=2,input(),sort="timestamp+desc")
+----
+
+(Note that the sort spec in the `top` decorator must match the sort spec in the
+handler parameter).
+
+Here's an example of using `unique` decorator:
+
+[source,text]
+----
+http://localhost:8983/solr/core_name/export?q=my-query&sort=reporter+desc,&fl=reporter&expr=unique(input(),over="reporter")
+----
+
+(Note that the `over` parameter must use one of the fields requested in the `fl` parameter).
+
 == Distributed Support
 
 See the section <<streaming-expressions.adoc#streaming-expressions,Streaming Expressions>> for distributed support.
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/Tuple.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/Tuple.java
index 4eea55e..2bdb2aa 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/Tuple.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/Tuple.java
@@ -41,12 +41,27 @@ public class Tuple implements Cloneable, MapWriter {
    *  The EOF Tuple will not contain a record from the stream, but it may contain
    *  metrics/aggregates gathered by underlying streams.
    * */
-
   public boolean EOF;
+  /**
+   * When EXCEPTION field is true the Tuple marks an exception in the stream
+   * and the corresponding "EXCEPTION" field contains a related message.
+   */
   public boolean EXCEPTION;
 
+  /**
+   * Tuple fields.
+   * @deprecated use {@link #getFields()} instead of this public field.
+   */
   public Map<Object, Object> fields = new HashMap<>(2);
+  /**
+   * External serializable field names.
+   * @deprecated use {@link #getFieldNames()} instead of this public field.
+   */
   public List<String> fieldNames;
+  /**
+   * Mapping of external field names to internal tuple field names.
+   * @deprecated use {@link #getFieldLabels()} instead of this public field.
+   */
   public Map<String, String> fieldLabels;
 
   public Tuple() {
@@ -194,20 +209,59 @@ public class Tuple implements Cloneable, MapWriter {
     return (List<Double>)this.fields.get(key);
   }
 
+  /**
+   * Return all tuple fields and their values.
+   */
+  public Map<Object, Object> getFields() {
+    return this.fields;
+  }
+
+  /**
+   * Return all tuple fields.
+   * @deprecated use {@link #getFields()} instead.
+   */
+  @Deprecated(since = "8.6.0")
   public Map getMap() {
     return this.fields;
   }
 
+  /**
+   * This represents the mapping of external field labels to the tuple's
+   * internal field names if they are different from field names.
+   * @return field labels or null
+   */
+  public Map<String, String> getFieldLabels() {
+    return fieldLabels;
+  }
+
+  public void setFieldLabels(Map<String, String> fieldLabels) {
+    this.fieldLabels = fieldLabels;
+  }
+
+  /**
+   * A list of field names to serialize. This list (together with
+   * the mapping in {@link #getFieldLabels()} determines what tuple values
+   * are serialized and their external (serialized) names.
+   * @return list of external field names or null
+   */
+  public List<String> getFieldNames() {
+    return fieldNames;
+  }
+
+  public void setFieldNames(List<String> fieldNames) {
+    this.fieldNames = fieldNames;
+  }
+
   public List<Map> getMaps(Object key) {
-    return (List<Map>)this.fields.get(key);
+    return (List<Map>) this.fields.get(key);
   }
 
   public void setMaps(Object key, List<Map> maps) {
     this.fields.put(key, maps);
   }
 
-  public Map<String,Map> getMetrics() {
-    return (Map<String,Map>)this.fields.get(StreamParams.METRICS);
+  public Map<String, Map> getMetrics() {
+    return (Map<String, Map>) this.fields.get(StreamParams.METRICS);
   }
 
   public void setMetrics(Map<String, Map> metrics) {
@@ -221,7 +275,7 @@ public class Tuple implements Cloneable, MapWriter {
   }
   
   public void merge(Tuple other) {
-    fields.putAll(other.getMap());
+    fields.putAll(other.getFields());
   }
 
   @Override
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/RecursiveEvaluator.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/RecursiveEvaluator.java
index f474f43..c7386bb 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/RecursiveEvaluator.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/RecursiveEvaluator.java
@@ -144,8 +144,8 @@ public abstract class RecursiveEvaluator implements StreamEvaluator, ValueWorker
 
       Tuple tuple = (Tuple)value;
       Tuple newTuple = new Tuple();
-      for(Object o : tuple.fields.keySet()) {
-        Object v = tuple.fields.get(o);
+      for(Object o : tuple.getFields().keySet()) {
+        Object v = tuple.get(o);
         newTuple.put(o, normalizeOutputType(v));
       }
       return newTuple;
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/SetValueEvaluator.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/SetValueEvaluator.java
index 47ef0ec..c56ecc2 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/SetValueEvaluator.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/SetValueEvaluator.java
@@ -45,7 +45,7 @@ public class SetValueEvaluator extends RecursiveObjectEvaluator implements ManyV
         value = ((String)value).replace("\"", "");
       }
       key = key.replace("\"", "");
-      Tuple newTuple = new Tuple(tuple.fields);
+      Tuple newTuple = tuple.clone();
       newTuple.put(key, value);
       return newTuple;
     } else {
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/GroupOperation.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/GroupOperation.java
index bd3250e..59d83c5 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/GroupOperation.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/GroupOperation.java
@@ -107,7 +107,7 @@ public class GroupOperation implements ReduceOperation {
   public Tuple reduce() {
     LinkedList ll = new LinkedList();
     while(priorityQueue.size() > 0) {
-      ll.addFirst(priorityQueue.poll().getMap());
+      ll.addFirst(priorityQueue.poll().getFields());
       //This will clear priority queue and so it will be ready for the next group.
     }
 
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/CommitStream.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/CommitStream.java
index b29ea09..5885862 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/CommitStream.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/CommitStream.java
@@ -123,7 +123,7 @@ public class CommitStream extends TupleStream implements Expressible {
       // if the read document contains field 'batchIndexed' then it's a summary
       // document and we can update our count based on it's value. If not then 
       // just increment by 1
-      if(tuple.fields.containsKey(UpdateStream.BATCH_INDEXED_FIELD_NAME) && isInteger(tuple.getString(UpdateStream.BATCH_INDEXED_FIELD_NAME))){
+      if(tuple.getFields().containsKey(UpdateStream.BATCH_INDEXED_FIELD_NAME) && isInteger(tuple.getString(UpdateStream.BATCH_INDEXED_FIELD_NAME))){
         docsSinceCommit += Integer.parseInt(tuple.getString(UpdateStream.BATCH_INDEXED_FIELD_NAME));
       }
       else{
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/DaemonStream.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/DaemonStream.java
index 0960bf7..962b61a 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/DaemonStream.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/DaemonStream.java
@@ -337,7 +337,7 @@ public class DaemonStream extends TupleStream implements Expressible {
               Tuple tuple = tupleStream.read();
               if (tuple.EOF) {
                 errors = 0; // Reset errors on successful run.
-                if (tuple.fields.containsKey("sleepMillis")) {
+                if (tuple.getFields().containsKey("sleepMillis")) {
                   this.sleepMillis = tuple.getLong("sleepMillis");
 
                   if(terminate && sleepMillis > 0) {
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/GetStream.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/GetStream.java
index 54a44b0..8b82761 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/GetStream.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/GetStream.java
@@ -90,7 +90,7 @@ public class GetStream extends TupleStream implements Expressible {
   public Tuple read() throws IOException {
     if (tupleIterator.hasNext()) {
       Tuple t = tupleIterator.next();
-      return new Tuple(t.fields);
+      return t.clone();
     } else {
       return Tuple.EOF();
     }
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/PlotStream.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/PlotStream.java
index 842cad3..142e3d0 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/PlotStream.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/PlotStream.java
@@ -195,8 +195,8 @@ public class PlotStream extends TupleStream implements Expressible {
       values.put("data", xy);
 
       Tuple tup = new Tuple(values);
-      tup.fieldLabels = fieldLabels;
-      tup.fieldNames = fieldNames;
+      tup.setFieldLabels(fieldLabels);
+      tup.setFieldNames(fieldNames);
       return tup;
     }
   }
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/RollupStream.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/RollupStream.java
index 0de3634..cdd8641 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/RollupStream.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/RollupStream.java
@@ -18,10 +18,8 @@ package org.apache.solr.client.solrj.io.stream;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 
 import org.apache.solr.client.solrj.io.Tuple;
 import org.apache.solr.client.solrj.io.comp.HashKey;
@@ -206,15 +204,14 @@ public class RollupStream extends TupleStream implements Expressible {
             return tuple;
           }
 
-          Map<String,Object> map = new HashMap<String,Object>();
+          Tuple t = new Tuple();
           for(Metric metric : currentMetrics) {
-            map.put(metric.getIdentifier(), metric.getValue());
+            t.put(metric.getIdentifier(), metric.getValue());
           }
 
           for(int i=0; i<buckets.length; i++) {
-            map.put(buckets[i].toString(), currentKey.getParts()[i]);
+            t.put(buckets[i].toString(), currentKey.getParts()[i]);
           }
-          Tuple t = new Tuple(map);
           tupleStream.pushBack(tuple);
           finished = true;
           return t;
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/ScoreNodesStream.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/ScoreNodesStream.java
index a9900db..95aa700 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/ScoreNodesStream.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/ScoreNodesStream.java
@@ -191,7 +191,7 @@ public class ScoreNodesStream extends TupleStream implements Expressible
         node.put("field", bucket);
       }
 
-      if(!node.fields.containsKey("node")) {
+      if(!node.getFields().containsKey("node")) {
         throw new IOException("node field not present in the Tuple");
       }
 
@@ -236,7 +236,7 @@ public class ScoreNodesStream extends TupleStream implements Expressible
           String term = terms.getName(t);
           Number docFreq = terms.get(term);
           Tuple tuple = nodes.get(term);
-          if(!tuple.fields.containsKey(termFreq)) {
+          if(!tuple.getFields().containsKey(termFreq)) {
             throw new Exception("termFreq field not present in the Tuple");
           }
           Number termFreqValue = (Number)tuple.get(termFreq);
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/SelectStream.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/SelectStream.java
index 4ec4d36..aee9c4c 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/SelectStream.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/SelectStream.java
@@ -267,7 +267,7 @@ public class SelectStream extends TupleStream implements Expressible {
 
     streamContext.getTupleContext().clear();
 
-    for(Object fieldName : original.fields.keySet()){
+    for(Object fieldName : original.getFields().keySet()){
       workingForEvaluators.put(fieldName, original.get(fieldName));
       if(selectedFields.containsKey(fieldName)){
         workingToReturn.put(selectedFields.get(fieldName), original.get(fieldName));
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/TupStream.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/TupStream.java
index fc8f213..7dd6204 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/TupStream.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/TupStream.java
@@ -230,8 +230,8 @@ public class TupStream extends TupleStream implements Expressible {
       }
     }
     this.tup = new Tuple(values);
-    tup.fieldNames = fieldNames;
-    tup.fieldLabels = fieldLabels;
+    tup.setFieldNames(fieldNames);
+    tup.setFieldLabels(fieldLabels);
     // nothing to do here
   }
 
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/UpdateStream.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/UpdateStream.java
index 07f12be..453f842 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/UpdateStream.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/UpdateStream.java
@@ -19,10 +19,8 @@ package org.apache.solr.client.solrj.io.stream;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Optional;
 
 import org.apache.solr.client.solrj.SolrServerException;
@@ -298,7 +296,7 @@ public class UpdateStream extends TupleStream implements Expressible {
   
   private SolrInputDocument convertTupleToSolrDocument(Tuple tuple) {
     SolrInputDocument doc = new SolrInputDocument();
-    for (Object field : tuple.fields.keySet()) {
+    for (Object field : tuple.getFields().keySet()) {
 
       if (! (field.equals(CommonParams.VERSION_FIELD) && pruneVersionField)) {
         Object value = tuple.get(field);
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/ZplotStream.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/ZplotStream.java
index 6beedc4..ea6606c 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/ZplotStream.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/stream/ZplotStream.java
@@ -111,10 +111,7 @@ public class ZplotStream extends TupleStream implements Expressible {
     if(out.hasNext()) {
       return out.next();
     } else {
-      Map m = new HashMap();
-      m.put("EOF", true);
-      Tuple t = new Tuple(m);
-      return t;
+      return Tuple.EOF();
     }
   }
 
@@ -208,7 +205,7 @@ public class ZplotStream extends TupleStream implements Expressible {
       }
 
       //Generate the x axis if the tuples contain y and not x
-      if (outTuples.get(0).fields.containsKey("y") && !outTuples.get(0).fields.containsKey("x")) {
+      if (outTuples.get(0).getFields().containsKey("y") && !outTuples.get(0).getFields().containsKey("x")) {
         int x = 0;
         for (Tuple tuple : outTuples) {
           tuple.put("x", x++);
@@ -312,14 +309,14 @@ public class ZplotStream extends TupleStream implements Expressible {
         if(list.get(0) instanceof Tuple) {
           List<Tuple> tlist = (List<Tuple>)o;
           Tuple tuple = tlist.get(0);
-          if(tuple.fields.containsKey("N")) {
+          if(tuple.getFields().containsKey("N")) {
             for(Tuple t : tlist) {
               Tuple outtuple = new Tuple();
               outtuple.put("x", Precision.round(((double)t.get("mean")), 2));
               outtuple.put("y", t.get("prob"));
               outTuples.add(outtuple);
             }
-          } else if(tuple.fields.containsKey("count")) {
+          } else if(tuple.getFields().containsKey("count")) {
             for(Tuple t : tlist) {
               Tuple outtuple = new Tuple();
               outtuple.put("x", t.get("value"));
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/CloudAuthStreamTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/CloudAuthStreamTest.java
index a452465..e5426fd 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/CloudAuthStreamTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/CloudAuthStreamTest.java
@@ -522,7 +522,7 @@ public class CloudAuthStreamTest extends SolrCloudTestCase {
           final List<Tuple> tuples = getTuples(daemonCheck);
           assertEquals(1, tuples.size()); // our daemon;
           if (log.isInfoEnabled()) {
-            log.info("Current daemon status: {}", tuples.get(0).fields);
+            log.info("Current daemon status: {}", tuples.get(0).getFields());
           }
           assertEquals(daemonId + " should have never had a successful iteration",
                        Long.valueOf(0L), tuples.get(0).getLong("iterations"));
@@ -808,7 +808,7 @@ public class CloudAuthStreamTest extends SolrCloudTestCase {
       log.trace("TupleStream: {}", tupleStream);
       tupleStream.open();
       for (Tuple t = tupleStream.read(); !t.EOF; t = tupleStream.read()) {
-        log.trace("Tuple: {}", t.fields);
+        log.trace("Tuple: {}", t.getFields());
         tuples.add(t);
       }
     } finally {
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/JDBCStreamTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/JDBCStreamTest.java
index 2fbe101..8b74a66 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/JDBCStreamTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/JDBCStreamTest.java
@@ -642,7 +642,7 @@ public class JDBCStreamTest extends SolrCloudTestCase {
   protected boolean assertFields(List<Tuple> tuples, String ... fields) throws Exception{
     for(Tuple tuple : tuples){
       for(String field : fields){
-        if(!tuple.fields.containsKey(field)){
+        if(!tuple.getFields().containsKey(field)){
           throw new Exception(String.format(Locale.ROOT, "Expected field '%s' not found", field));
         }
       }
@@ -653,7 +653,7 @@ public class JDBCStreamTest extends SolrCloudTestCase {
   protected boolean assertNotFields(List<Tuple> tuples, String ... fields) throws Exception{
     for(Tuple tuple : tuples){
       for(String field : fields){
-        if(tuple.fields.containsKey(field)){
+        if(tuple.getFields().containsKey(field)){
           throw new Exception(String.format(Locale.ROOT, "Unexpected field '%s' found", field));
         }
       }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/SelectWithEvaluatorsTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/SelectWithEvaluatorsTest.java
index cf86691..744632b 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/SelectWithEvaluatorsTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/SelectWithEvaluatorsTest.java
@@ -167,7 +167,7 @@ public class SelectWithEvaluatorsTest extends SolrCloudTestCase {
   protected boolean assertFields(List<Tuple> tuples, String ... fields) throws Exception{
     for(Tuple tuple : tuples){
       for(String field : fields){
-        if(!tuple.fields.containsKey(field)){
+        if(!tuple.getFields().containsKey(field)){
           throw new Exception(String.format(Locale.ROOT, "Expected field '%s' not found", field));
         }
       }
@@ -177,7 +177,7 @@ public class SelectWithEvaluatorsTest extends SolrCloudTestCase {
   protected boolean assertNotFields(List<Tuple> tuples, String ... fields) throws Exception{
     for(Tuple tuple : tuples){
       for(String field : fields){
-        if(tuple.fields.containsKey(field)){
+        if(tuple.getFields().containsKey(field)){
           throw new Exception(String.format(Locale.ROOT, "Unexpected field '%s' found", field));
         }
       }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/StreamDecoratorTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/StreamDecoratorTest.java
index 73f6f9d..f57f655 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/StreamDecoratorTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/StreamDecoratorTest.java
@@ -2296,7 +2296,7 @@ public class StreamDecoratorTest extends SolrCloudTestCase {
       tuples = getTuples(stream);
       
       assertEquals(1, tuples.size());
-      assertFalse(tuples.get(0).fields.containsKey("extra_s"));
+      assertFalse(tuples.get(0).getFields().containsKey("extra_s"));
     
     } finally {
       solrClientCache.close();
@@ -4467,7 +4467,7 @@ public class StreamDecoratorTest extends SolrCloudTestCase {
   protected boolean assertFields(List<Tuple> tuples, String ... fields) throws Exception{
     for(Tuple tuple : tuples){
       for(String field : fields){
-        if(!tuple.fields.containsKey(field)){
+        if(!tuple.getFields().containsKey(field)){
           throw new Exception(String.format(Locale.ROOT, "Expected field '%s' not found", field));
         }
       }
@@ -4477,7 +4477,7 @@ public class StreamDecoratorTest extends SolrCloudTestCase {
   protected boolean assertNotFields(List<Tuple> tuples, String ... fields) throws Exception{
     for(Tuple tuple : tuples){
       for(String field : fields){
-        if(tuple.fields.containsKey(field)){
+        if(tuple.getFields().containsKey(field)){
           throw new Exception(String.format(Locale.ROOT, "Unexpected field '%s' found", field));
         }
       }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/StreamExpressionTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/StreamExpressionTest.java
index 7e5da9d..7288e7a 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/StreamExpressionTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/StreamExpressionTest.java
@@ -674,7 +674,7 @@ public class StreamExpressionTest extends SolrCloudTestCase {
       solrStream = new SolrStream(jetty.getBaseUrl().toString() + "/collection1", sParams);
       tuples4 = getTuples(solrStream);
       assert(tuples4.size() == 500);
-      Map fields = tuples4.get(0).fields;
+      Map fields = tuples4.get(0).getFields();
       assert(fields.containsKey("id"));
       assert(fields.containsKey("a_f"));
       assert(fields.containsKey("a_i"));
@@ -3028,7 +3028,7 @@ public class StreamExpressionTest extends SolrCloudTestCase {
       tuples = getTuples(stream);
       assertEquals(100, tuples.size());
       Tuple lastModel = tuples.get(0);
-      ClassificationEvaluation evaluation = ClassificationEvaluation.create(lastModel.fields);
+      ClassificationEvaluation evaluation = ClassificationEvaluation.create(lastModel.getFields());
       assertTrue(evaluation.getF1() >= 1.0);
       assertEquals(Math.log(5000.0 / (2500 + 1)), lastModel.getDoubles("idfs_ds").get(0), 0.0001);
       // make sure the tuples is retrieved in correct order