I committed a fix this sorry for the noise. Joel Bernstein http://joelsolr.blogspot.com/
On Fri, May 6, 2016 at 8:03 AM, Joel Bernstein <[email protected]> wrote: > Ok, I didn't realize that. I'll dig into it. > > Joel Bernstein > http://joelsolr.blogspot.com/ > > On Fri, May 6, 2016 at 1:40 AM, Chris Hostetter <[email protected]> > wrote: > >> >> Joel: adding /graph to the list of ImplicitPlugins has broken >> MinimalSchemaTest.testAllConfiguredHandlers (see recent jenkins failures) >> >> >> >> : Date: Thu, 5 May 2016 20:29:33 +0000 (UTC) >> : From: [email protected] >> : Reply-To: [email protected] >> : To: [email protected] >> : Subject: lucene-solr:master: SOLR-8972: Add GraphHandler and >> : GraphMLResponseWriter to support graph visualizations >> : >> : Repository: lucene-solr >> : Updated Branches: >> : refs/heads/master 7d4f38738 -> be1cb9a1c >> : >> : >> : SOLR-8972: Add GraphHandler and GraphMLResponseWriter to support graph >> visualizations >> : >> : >> : Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo >> : Commit: >> http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/be1cb9a1 >> : Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/be1cb9a1 >> : Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/be1cb9a1 >> : >> : Branch: refs/heads/master >> : Commit: be1cb9a1cde4dd426305f22620734d018f21dd82 >> : Parents: 7d4f387 >> : Author: jbernste <[email protected]> >> : Authored: Thu May 5 14:27:05 2016 -0400 >> : Committer: jbernste <[email protected]> >> : Committed: Thu May 5 16:36:19 2016 -0400 >> : >> : ---------------------------------------------------------------------- >> : .../src/java/org/apache/solr/core/SolrCore.java | 1 + >> : .../org/apache/solr/handler/GraphHandler.java | 282 >> +++++++++++++++++++ >> : .../solr/response/GraphMLResponseWriter.java | 167 +++++++++++ >> : solr/core/src/resources/ImplicitPlugins.json | 7 + >> : .../response/TestGraphMLResponseWriter.java | 155 ++++++++++ >> : .../solrj/io/graph/GraphExpressionTest.java | 173 +++++++++--- >> : .../solrj/io/stream/StreamExpressionTest.java | 1 - >> : 7 files changed, 743 insertions(+), 43 deletions(-) >> : ---------------------------------------------------------------------- >> : >> : >> : >> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/be1cb9a1/solr/core/src/java/org/apache/solr/core/SolrCore.java >> : ---------------------------------------------------------------------- >> : diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java >> b/solr/core/src/java/org/apache/solr/core/SolrCore.java >> : index b94b3d8..d5cde16 100644 >> : --- a/solr/core/src/java/org/apache/solr/core/SolrCore.java >> : +++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java >> : @@ -2111,6 +2111,7 @@ public final class SolrCore implements >> SolrInfoMBean, Closeable { >> : m.put("standard", m.get("xml")); >> : m.put(CommonParams.JSON, new JSONResponseWriter()); >> : m.put("geojson", new GeoJSONResponseWriter()); >> : + m.put("graphml", new GraphMLResponseWriter()); >> : m.put("python", new PythonResponseWriter()); >> : m.put("php", new PHPResponseWriter()); >> : m.put("phps", new PHPSerializedResponseWriter()); >> : >> : >> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/be1cb9a1/solr/core/src/java/org/apache/solr/handler/GraphHandler.java >> : ---------------------------------------------------------------------- >> : diff --git >> a/solr/core/src/java/org/apache/solr/handler/GraphHandler.java >> b/solr/core/src/java/org/apache/solr/handler/GraphHandler.java >> : new file mode 100644 >> : index 0000000..a6e2ce1 >> : --- /dev/null >> : +++ b/solr/core/src/java/org/apache/solr/handler/GraphHandler.java >> : @@ -0,0 +1,282 @@ >> : +package org.apache.solr.handler; >> : + >> : +/* >> : + * Licensed to the Apache Software Foundation (ASF) under one or more >> : + * contributor license agreements. See the NOTICE file distributed >> with >> : + * this work for additional information regarding copyright ownership. >> : + * The ASF licenses this file to You under the Apache License, Version >> 2.0 >> : + * (the "License"); you may not use this file except in compliance with >> : + * the License. You may obtain a copy of the License at >> : + * >> : + * http://www.apache.org/licenses/LICENSE-2.0 >> : + * >> : + * Unless required by applicable law or agreed to in writing, software >> : + * distributed under the License is distributed on an "AS IS" BASIS, >> : + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or >> implied. >> : + * See the License for the specific language governing permissions and >> : + * limitations under the License. >> : + */ >> : + >> : +import java.io.IOException; >> : +import java.lang.invoke.MethodHandles; >> : +import java.util.HashMap; >> : +import java.util.List; >> : +import java.util.Map; >> : +import java.util.Map.Entry; >> : + >> : +import org.apache.solr.client.solrj.io.SolrClientCache; >> : +import org.apache.solr.client.solrj.io.Tuple; >> : +import org.apache.solr.client.solrj.io.comp.StreamComparator; >> : +import org.apache.solr.client.solrj.io.graph.GatherNodesStream; >> : +import org.apache.solr.client.solrj.io.graph.ShortestPathStream; >> : +import org.apache.solr.client.solrj.io.graph.Traversal; >> : +import org.apache.solr.client.solrj.io.ops.ConcatOperation; >> : +import org.apache.solr.client.solrj.io.ops.DistinctOperation; >> : +import org.apache.solr.client.solrj.io.ops.GroupOperation; >> : +import org.apache.solr.client.solrj.io.ops.ReplaceOperation; >> : +import org.apache.solr.client.solrj.io.stream.*; >> : +import org.apache.solr.client.solrj.io.stream.expr.Explanation; >> : +import org.apache.solr.client.solrj.io.stream.expr.Expressible; >> : +import org.apache.solr.client.solrj.io.stream.expr.StreamFactory; >> : +import org.apache.solr.client.solrj.io.stream.metrics.CountMetric; >> : +import org.apache.solr.client.solrj.io.stream.metrics.MaxMetric; >> : +import org.apache.solr.client.solrj.io.stream.metrics.MeanMetric; >> : +import org.apache.solr.client.solrj.io.stream.metrics.MinMetric; >> : +import org.apache.solr.client.solrj.io.stream.metrics.SumMetric; >> : +import org.apache.solr.common.SolrException; >> : +import org.apache.solr.common.params.CommonParams; >> : +import org.apache.solr.common.params.ModifiableSolrParams; >> : +import org.apache.solr.common.params.SolrParams; >> : +import org.apache.solr.common.util.NamedList; >> : +import org.apache.solr.core.CloseHook; >> : +import org.apache.solr.core.CoreContainer; >> : +import org.apache.solr.core.SolrCore; >> : +import org.apache.solr.request.SolrQueryRequest; >> : +import org.apache.solr.response.SolrQueryResponse; >> : +import org.apache.solr.security.AuthorizationContext; >> : +import org.apache.solr.security.PermissionNameProvider; >> : +import org.apache.solr.util.plugin.SolrCoreAware; >> : +import org.slf4j.Logger; >> : +import org.slf4j.LoggerFactory; >> : + >> : +public class GraphHandler extends RequestHandlerBase implements >> SolrCoreAware, PermissionNameProvider { >> : + >> : + private StreamFactory streamFactory = new StreamFactory(); >> : + private static final Logger logger = >> LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); >> : + private String coreName; >> : + >> : + @Override >> : + public PermissionNameProvider.Name >> getPermissionName(AuthorizationContext request) { >> : + return PermissionNameProvider.Name.READ_PERM; >> : + } >> : + >> : + public void inform(SolrCore core) { >> : + >> : + /* The stream factory will always contain the zkUrl for the given >> collection >> : + * Adds default streams with their corresponding function names. >> These >> : + * defaults can be overridden or added to in the solrConfig in the >> stream >> : + * RequestHandler def. Example config override >> : + * <lst name="streamFunctions"> >> : + * <str >> name="group">org.apache.solr.client.solrj.io.stream.ReducerStream</str> >> : + * <str >> name="count">org.apache.solr.client.solrj.io.stream.RecordCountStream</str> >> : + * </lst> >> : + * */ >> : + >> : + String defaultCollection = null; >> : + String defaultZkhost = null; >> : + CoreContainer coreContainer = >> core.getCoreDescriptor().getCoreContainer(); >> : + this.coreName = core.getName(); >> : + >> : + if(coreContainer.isZooKeeperAware()) { >> : + defaultCollection = core.getCoreDescriptor().getCollectionName(); >> : + defaultZkhost = >> core.getCoreDescriptor().getCoreContainer().getZkController().getZkServerAddress(); >> : + streamFactory.withCollectionZkHost(defaultCollection, >> defaultZkhost); >> : + streamFactory.withDefaultZkHost(defaultZkhost); >> : + } >> : + >> : + streamFactory >> : + // streams >> : + .withFunctionName("search", CloudSolrStream.class) >> : + .withFunctionName("merge", MergeStream.class) >> : + .withFunctionName("unique", UniqueStream.class) >> : + .withFunctionName("top", RankStream.class) >> : + .withFunctionName("group", GroupOperation.class) >> : + .withFunctionName("reduce", ReducerStream.class) >> : + .withFunctionName("parallel", ParallelStream.class) >> : + .withFunctionName("rollup", RollupStream.class) >> : + .withFunctionName("stats", StatsStream.class) >> : + .withFunctionName("innerJoin", InnerJoinStream.class) >> : + .withFunctionName("leftOuterJoin", LeftOuterJoinStream.class) >> : + .withFunctionName("hashJoin", HashJoinStream.class) >> : + .withFunctionName("outerHashJoin", OuterHashJoinStream.class) >> : + .withFunctionName("facet", FacetStream.class) >> : + .withFunctionName("update", UpdateStream.class) >> : + .withFunctionName("jdbc", JDBCStream.class) >> : + .withFunctionName("intersect", IntersectStream.class) >> : + .withFunctionName("complement", ComplementStream.class) >> : + .withFunctionName("daemon", DaemonStream.class) >> : + .withFunctionName("topic", TopicStream.class) >> : + .withFunctionName("shortestPath", ShortestPathStream.class) >> : + .withFunctionName("gatherNodes", GatherNodesStream.class) >> : + .withFunctionName("sort", SortStream.class) >> : + >> : + >> : + // metrics >> : + .withFunctionName("min", MinMetric.class) >> : + .withFunctionName("max", MaxMetric.class) >> : + .withFunctionName("avg", MeanMetric.class) >> : + .withFunctionName("sum", SumMetric.class) >> : + .withFunctionName("count", CountMetric.class) >> : + >> : + // tuple manipulation operations >> : + .withFunctionName("replace", ReplaceOperation.class) >> : + .withFunctionName("concat", ConcatOperation.class) >> : + >> : + // stream reduction operations >> : + .withFunctionName("group", GroupOperation.class) >> : + .withFunctionName("distinct", DistinctOperation.class); >> : + >> : + // This pulls all the overrides and additions from the config >> : + Object functionMappingsObj = initArgs.get("streamFunctions"); >> : + if(null != functionMappingsObj){ >> : + NamedList<?> functionMappings = >> (NamedList<?>)functionMappingsObj; >> : + for(Entry<String,?> functionMapping : functionMappings){ >> : + Class<?> clazz = >> core.getResourceLoader().findClass((String)functionMapping.getValue(), >> Expressible.class); >> : + streamFactory.withFunctionName(functionMapping.getKey(), >> clazz); >> : + } >> : + } >> : + } >> : + >> : + public void handleRequestBody(SolrQueryRequest req, >> SolrQueryResponse rsp) throws Exception { >> : + SolrParams params = req.getParams(); >> : + params = adjustParams(params); >> : + req.setParams(params); >> : + >> : + >> : + TupleStream tupleStream = null; >> : + >> : + try { >> : + tupleStream = >> this.streamFactory.constructStream(params.get("expr")); >> : + } catch (Exception e) { >> : + //Catch exceptions that occur while the stream is being created. >> This will include streaming expression parse rules. >> : + SolrException.log(logger, e); >> : + Map requestContext = req.getContext(); >> : + requestContext.put("stream", new DummyErrorStream(e)); >> : + return; >> : + } >> : + >> : + StreamContext context = new StreamContext(); >> : + context.setSolrClientCache(StreamHandler.clientCache); >> : + context.put("core", this.coreName); >> : + Traversal traversal = new Traversal(); >> : + context.put("traversal", traversal); >> : + tupleStream.setStreamContext(context); >> : + Map requestContext = req.getContext(); >> : + requestContext.put("stream", new TimerStream(new >> ExceptionStream(tupleStream))); >> : + requestContext.put("traversal", traversal); >> : + } >> : + >> : + public String getDescription() { >> : + return "StreamHandler"; >> : + } >> : + >> : + public String getSource() { >> : + return null; >> : + } >> : + >> : + >> : + public static class DummyErrorStream extends TupleStream { >> : + private Exception e; >> : + >> : + public DummyErrorStream(Exception e) { >> : + this.e = e; >> : + } >> : + public StreamComparator getStreamSort() { >> : + return null; >> : + } >> : + >> : + public void close() { >> : + } >> : + >> : + public void open() { >> : + } >> : + >> : + public Exception getException() { >> : + return this.e; >> : + } >> : + >> : + public void setStreamContext(StreamContext context) { >> : + } >> : + >> : + public List<TupleStream> children() { >> : + return null; >> : + } >> : + >> : + @Override >> : + public Explanation toExplanation(StreamFactory factory) throws >> IOException { >> : + return null; >> : + } >> : + >> : + public Tuple read() { >> : + String msg = e.getMessage(); >> : + Map m = new HashMap(); >> : + m.put("EOF", true); >> : + m.put("EXCEPTION", msg); >> : + return new Tuple(m); >> : + } >> : + } >> : + >> : + >> : + private SolrParams adjustParams(SolrParams params) { >> : + ModifiableSolrParams adjustedParams = new ModifiableSolrParams(); >> : + adjustedParams.add(params); >> : + adjustedParams.add(CommonParams.OMIT_HEADER, "true"); >> : + return adjustedParams; >> : + } >> : + >> : + public static class TimerStream extends TupleStream { >> : + >> : + private long begin; >> : + private TupleStream tupleStream; >> : + >> : + public TimerStream(TupleStream tupleStream) { >> : + this.tupleStream = tupleStream; >> : + } >> : + >> : + public StreamComparator getStreamSort() { >> : + return this.tupleStream.getStreamSort(); >> : + } >> : + >> : + public void close() throws IOException { >> : + this.tupleStream.close(); >> : + } >> : + >> : + public void open() throws IOException { >> : + this.begin = System.nanoTime(); >> : + this.tupleStream.open(); >> : + } >> : + >> : + public void setStreamContext(StreamContext context) { >> : + this.tupleStream.setStreamContext(context); >> : + } >> : + >> : + public List<TupleStream> children() { >> : + return this.tupleStream.children(); >> : + } >> : + >> : + @Override >> : + public Explanation toExplanation(StreamFactory factory) throws >> IOException { >> : + return null; >> : + } >> : + >> : + public Tuple read() throws IOException { >> : + Tuple tuple = this.tupleStream.read(); >> : + if(tuple.EOF) { >> : + long totalTime = (System.nanoTime() - begin) / 1000000; >> : + tuple.fields.put("RESPONSE_TIME", totalTime); >> : + } >> : + return tuple; >> : + } >> : + } >> : + >> : +} >> : \ No newline at end of file >> : >> : >> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/be1cb9a1/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java >> : ---------------------------------------------------------------------- >> : diff --git >> a/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java >> b/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java >> : new file mode 100644 >> : index 0000000..d941991 >> : --- /dev/null >> : +++ >> b/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java >> : @@ -0,0 +1,167 @@ >> : +package org.apache.solr.response; >> : + >> : +/* >> : + * Licensed to the Apache Software Foundation (ASF) under one or more >> : + * contributor license agreements. See the NOTICE file distributed >> with >> : + * this work for additional information regarding copyright ownership. >> : + * The ASF licenses this file to You under the Apache License, Version >> 2.0 >> : + * (the "License"); you may not use this file except in compliance with >> : + * the License. You may obtain a copy of the License at >> : + * >> : + * http://www.apache.org/licenses/LICENSE-2.0 >> : + * >> : + * Unless required by applicable law or agreed to in writing, software >> : + * distributed under the License is distributed on an "AS IS" BASIS, >> : + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or >> implied. >> : + * See the License for the specific language governing permissions and >> : + * limitations under the License. >> : + */ >> : + >> : +import java.io.IOException; >> : +import java.io.PrintWriter; >> : +import java.io.Writer; >> : +import java.lang.invoke.MethodHandles; >> : +import java.util.Iterator; >> : +import java.util.List; >> : +import java.util.ArrayList; >> : + >> : +import org.apache.solr.client.solrj.io.graph.Traversal; >> : +import org.apache.solr.client.solrj.io.stream.TupleStream; >> : +import org.apache.solr.client.solrj.io.Tuple; >> : +import org.apache.solr.common.util.NamedList; >> : +import org.apache.solr.handler.GraphHandler; >> : +import org.apache.solr.request.SolrQueryRequest; >> : +import org.slf4j.Logger; >> : +import org.slf4j.LoggerFactory; >> : + >> : + >> : +public class GraphMLResponseWriter implements QueryResponseWriter { >> : + >> : + private static final Logger logger = >> LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); >> : + >> : + public void init(NamedList args) { >> : + /* NOOP */ >> : + } >> : + >> : + public String getContentType(SolrQueryRequest req, SolrQueryResponse >> res) { >> : + return "application/xml"; >> : + } >> : + >> : + public void write(Writer writer, SolrQueryRequest req, >> SolrQueryResponse res) throws IOException { >> : + >> : + Exception e1 = res.getException(); >> : + if(e1 != null) { >> : + e1.printStackTrace(new PrintWriter(writer)); >> : + return; >> : + } >> : + >> : + TupleStream stream = (TupleStream)req.getContext().get("stream"); >> : + >> : + if(stream instanceof GraphHandler.DummyErrorStream) { >> : + GraphHandler.DummyErrorStream d = >> (GraphHandler.DummyErrorStream)stream; >> : + Exception e = d.getException(); >> : + e.printStackTrace(new PrintWriter(writer)); >> : + return; >> : + } >> : + >> : + >> : + Traversal traversal = (Traversal)req.getContext().get("traversal"); >> : + PrintWriter printWriter = new PrintWriter(writer); >> : + >> : + try { >> : + >> : + stream.open(); >> : + >> : + Tuple tuple = null; >> : + >> : + int edgeCount = 0; >> : + >> : + printWriter.println("<?xml version=\"1.0\" >> encoding=\"UTF-8\"?>"); >> : + printWriter.println("<graphml xmlns=\" >> http://graphml.graphdrawing.org/xmlns\" "); >> : + printWriter.println("xmlns:xsi=\" >> http://www.w3.org/2001/XMLSchema-instance\" "); >> : + printWriter.print("xsi:schemaLocation=\" >> http://graphml.graphdrawing.org/xmlns "); >> : + printWriter.println(" >> http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">"); >> : + >> : + printWriter.println("<graph id=\"G\" edgedefault=\"directed\">"); >> : + >> : + while (true) { >> : + //Output the graph >> : + tuple = stream.read(); >> : + if (tuple.EOF) { >> : + break; >> : + } >> : + >> : + String id = tuple.getString("node"); >> : + >> : + if (traversal.isMultiCollection()) { >> : + id = tuple.getString("collection") + "." + id; >> : + } >> : + >> : + writer.write("<node id=\""+replace(id)+"\""); >> : + >> : + List<String> outfields = new ArrayList(); >> : + Iterator<String> keys = tuple.fields.keySet().iterator(); >> : + while(keys.hasNext()) { >> : + String key = keys.next(); >> : + if(key.equals("node") || key.equals("ancestors") || >> key.equals("collection")) { >> : + continue; >> : + } else { >> : + outfields.add(key); >> : + } >> : + } >> : + >> : + if (outfields.size() > 0) { >> : + printWriter.println(">"); >> : + for (String nodeAttribute : outfields) { >> : + Object o = tuple.get(nodeAttribute); >> : + if (o != null) { >> : + printWriter.println("<data key=\""+nodeAttribute+"\">" + >> o.toString() + "</data>"); >> : + } >> : + } >> : + printWriter.println("</node>"); >> : + } else { >> : + printWriter.println("/>"); >> : + } >> : + >> : + List<String> ancestors = tuple.getStrings("ancestors"); >> : + >> : + if(ancestors != null) { >> : + for (String ancestor : ancestors) { >> : + ++edgeCount; >> : + writer.write("<edge id=\"" + edgeCount + "\" "); >> : + writer.write(" source=\"" + replace(ancestor) + "\" "); >> : + printWriter.println(" target=\"" + replace(id) + "\"/>"); >> : + } >> : + } >> : + } >> : + >> : + writer.write("</graph></graphml>"); >> : + } finally { >> : + stream.close(); >> : + } >> : + } >> : + >> : + private String replace(String s) { >> : + if(s.indexOf(">") > -1) { >> : + s = s.replace(">", ">"); >> : + } >> : + >> : + if(s.indexOf("<") > -1) { >> : + s = s.replace("<", "<"); >> : + } >> : + >> : + if(s.indexOf("\"")> -1) { >> : + s = s.replace("\"", """); >> : + } >> : + >> : + if(s.indexOf("'") > -1) { >> : + s = s.replace("'", "'"); >> : + } >> : + >> : + if(s.indexOf("&") > -1) { >> : + s = s.replace("&", "&"); >> : + } >> : + >> : + return s; >> : + } >> : +} >> : \ No newline at end of file >> : >> : >> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/be1cb9a1/solr/core/src/resources/ImplicitPlugins.json >> : ---------------------------------------------------------------------- >> : diff --git a/solr/core/src/resources/ImplicitPlugins.json >> b/solr/core/src/resources/ImplicitPlugins.json >> : index 8c0549a..325bf91 100644 >> : --- a/solr/core/src/resources/ImplicitPlugins.json >> : +++ b/solr/core/src/resources/ImplicitPlugins.json >> : @@ -84,6 +84,13 @@ >> : "distrib": false >> : } >> : }, >> : + "/graph": { >> : + "class": "solr.GraphHandler", >> : + "invariants": { >> : + "wt": "graphml", >> : + "distrib": false >> : + } >> : + }, >> : "/stream": { >> : "class": "solr.StreamHandler", >> : "invariants": { >> : >> : >> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/be1cb9a1/solr/core/src/test/org/apache/solr/response/TestGraphMLResponseWriter.java >> : ---------------------------------------------------------------------- >> : diff --git >> a/solr/core/src/test/org/apache/solr/response/TestGraphMLResponseWriter.java >> b/solr/core/src/test/org/apache/solr/response/TestGraphMLResponseWriter.java >> : new file mode 100644 >> : index 0000000..283f64d >> : --- /dev/null >> : +++ >> b/solr/core/src/test/org/apache/solr/response/TestGraphMLResponseWriter.java >> : @@ -0,0 +1,155 @@ >> : +package org.apache.solr.response; >> : + >> : +/* >> : + * Licensed to the Apache Software Foundation (ASF) under one or more >> : + * contributor license agreements. See the NOTICE file distributed >> with >> : + * this work for additional information regarding copyright ownership. >> : + * The ASF licenses this file to You under the Apache License, Version >> 2.0 >> : + * (the "License"); you may not use this file except in compliance with >> : + * the License. You may obtain a copy of the License at >> : + * >> : + * http://www.apache.org/licenses/LICENSE-2.0 >> : + * >> : + * Unless required by applicable law or agreed to in writing, software >> : + * distributed under the License is distributed on an "AS IS" BASIS, >> : + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or >> implied. >> : + * See the License for the specific language governing permissions and >> : + * limitations under the License. >> : + */ >> : + >> : +import java.io.StringWriter; >> : +import java.util.Map; >> : +import java.util.HashMap; >> : +import java.util.List; >> : +import java.util.ArrayList; >> : +import java.util.Iterator; >> : + >> : +import org.apache.solr.SolrTestCaseJ4; >> : +import org.apache.solr.client.solrj.io.comp.StreamComparator; >> : +import org.apache.solr.client.solrj.io.graph.Traversal; >> : +import org.apache.solr.client.solrj.io.stream.TupleStream; >> : +import org.apache.solr.client.solrj.io.stream.StreamContext; >> : +import org.apache.solr.client.solrj.io.stream.expr.StreamFactory; >> : +import org.apache.solr.client.solrj.io.Tuple; >> : +import org.apache.solr.client.solrj.io.stream.expr.Explanation; >> : +import org.apache.solr.request.SolrQueryRequest; >> : +import org.junit.BeforeClass; >> : +import org.junit.Test; >> : + >> : +public class TestGraphMLResponseWriter extends SolrTestCaseJ4 { >> : + @BeforeClass >> : + public static void beforeClass() throws Exception { >> : + System.setProperty("enable.update.log", "false"); // schema12 >> doesn't support _version_ >> : + initCore("solrconfig.xml","schema12.xml"); >> : + } >> : + >> : + @Test >> : + public void testGraphMLOutput() throws Exception { >> : + SolrQueryRequest request = req("blah", "blah"); // Just need a >> request to attach the stream and traversal to. >> : + SolrQueryResponse response = new SolrQueryResponse(); >> : + Map context = request.getContext(); >> : + TupleStream stream = new TestStream(); //Simulates a >> GatherNodesStream >> : + Traversal traversal = new Traversal(); >> : + context.put("traversal", traversal); >> : + context.put("stream", stream); >> : + StringWriter writer = new StringWriter(); >> : + >> : + GraphMLResponseWriter graphMLResponseWriter = new >> GraphMLResponseWriter(); >> : + graphMLResponseWriter.write(writer, request, response); >> : + String graphML = writer.toString(); >> : + >> : + //Validate the nodes >> : + String error = h.validateXPath(graphML, >> : + "//graph/node[1][@id ='bill']", >> : + "//graph/node[2][@id ='jim']", >> : + "//graph/node[3][@id ='max']"); >> : + if(error != null) { >> : + throw new Exception(error); >> : + } >> : + //Validate the edges >> : + error = h.validateXPath(graphML, >> : + "//graph/edge[1][@source ='jim']", >> : + "//graph/edge[1][@target ='bill']", >> : + "//graph/edge[2][@source ='max']", >> : + "//graph/edge[2][@target ='bill']", >> : + "//graph/edge[3][@source ='max']", >> : + "//graph/edge[3][@target ='jim']", >> : + "//graph/edge[4][@source ='jim']", >> : + "//graph/edge[4][@target ='max']" >> : + ); >> : + >> : + if(error != null) { >> : + throw new Exception(error); >> : + } >> : + >> : + } >> : + >> : + private class TestStream extends TupleStream { >> : + >> : + private Iterator<Tuple> tuples; >> : + >> : + public TestStream() { >> : + //Create some nodes >> : + List<Tuple> testTuples = new ArrayList(); >> : + Map m1 = new HashMap(); >> : + >> : + List<String> an1 = new ArrayList(); >> : + an1.add("jim"); >> : + an1.add("max"); >> : + m1.put("node", "bill"); >> : + m1.put("ancestors", an1); >> : + testTuples.add(new Tuple(m1)); >> : + >> : + Map m2 = new HashMap(); >> : + List<String> an2 = new ArrayList(); >> : + an2.add("max"); >> : + m2.put("node", "jim"); >> : + m2.put("ancestors", an2); >> : + testTuples.add(new Tuple(m2)); >> : + >> : + Map m3 = new HashMap(); >> : + List<String> an3 = new ArrayList(); >> : + an3.add("jim"); >> : + m3.put("node", "max"); >> : + m3.put("ancestors", an3); >> : + testTuples.add(new Tuple(m3)); >> : + >> : + tuples = testTuples.iterator(); >> : + } >> : + >> : + public StreamComparator getStreamSort() { >> : + return null; >> : + } >> : + >> : + public void close() { >> : + >> : + } >> : + >> : + public void open() { >> : + >> : + } >> : + >> : + public List<TupleStream> children() { >> : + return null; >> : + } >> : + >> : + public Tuple read() { >> : + if(tuples.hasNext()) { >> : + return tuples.next(); >> : + } else { >> : + Map map = new HashMap(); >> : + map.put("EOF", true); >> : + return new Tuple(map); >> : + } >> : + } >> : + >> : + public void setStreamContext(StreamContext streamContext) { >> : + >> : + } >> : + >> : + public Explanation toExplanation(StreamFactory factory) { >> : + return null; >> : + } >> : + >> : + } >> : +} >> : >> : >> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/be1cb9a1/solr/solrj/src/test/org/apache/solr/client/solrj/io/graph/GraphExpressionTest.java >> : ---------------------------------------------------------------------- >> : diff --git >> a/solr/solrj/src/test/org/apache/solr/client/solrj/io/graph/GraphExpressionTest.java >> b/solr/solrj/src/test/org/apache/solr/client/solrj/io/graph/GraphExpressionTest.java >> : index 53f7126..c429fe8 100644 >> : --- >> a/solr/solrj/src/test/org/apache/solr/client/solrj/io/graph/GraphExpressionTest.java >> : +++ >> b/solr/solrj/src/test/org/apache/solr/client/solrj/io/graph/GraphExpressionTest.java >> : @@ -18,6 +18,8 @@ package org.apache.solr.client.solrj.io.graph; >> : */ >> : >> : import java.io.IOException; >> : +import java.io.InputStreamReader; >> : +import java.io.InputStream; >> : import java.util.ArrayList; >> : import java.util.Collections; >> : import java.util.HashMap; >> : @@ -28,6 +30,10 @@ import java.util.Set; >> : >> : import org.apache.lucene.util.LuceneTestCase; >> : import org.apache.lucene.util.LuceneTestCase.Slow; >> : +import org.apache.solr.client.solrj.SolrRequest; >> : +import org.apache.solr.client.solrj.embedded.JettySolrRunner; >> : +import org.apache.solr.client.solrj.impl.HttpSolrClient; >> : +import org.apache.solr.client.solrj.impl.InputStreamResponseParser; >> : import org.apache.solr.client.solrj.io.SolrClientCache; >> : import org.apache.solr.client.solrj.io.Tuple; >> : import org.apache.solr.client.solrj.io.comp.ComparatorOrder; >> : @@ -43,9 +49,12 @@ import >> org.apache.solr.client.solrj.io.stream.metrics.MeanMetric; >> : import org.apache.solr.client.solrj.io.stream.metrics.MinMetric; >> : import org.apache.solr.client.solrj.io.stream.metrics.SumMetric; >> : import org.apache.solr.client.solrj.request.CollectionAdminRequest; >> : +import org.apache.solr.client.solrj.request.QueryRequest; >> : import org.apache.solr.client.solrj.request.UpdateRequest; >> : import org.apache.solr.cloud.AbstractDistribZkTestBase; >> : import org.apache.solr.cloud.SolrCloudTestCase; >> : +import org.apache.solr.common.params.ModifiableSolrParams; >> : +import org.apache.solr.common.util.NamedList; >> : import org.junit.Before; >> : import org.junit.BeforeClass; >> : import org.junit.Test; >> : @@ -266,8 +275,8 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : .withFunctionName("max", MaxMetric.class); >> : >> : String expr = "gatherNodes(collection1, " + >> : - "walk=\"product1->product_s\"," + >> : - "gather=\"basket_s\")"; >> : + "walk=\"product1->product_s\"," + >> : + "gather=\"basket_s\")"; >> : >> : stream = (GatherNodesStream)factory.constructStream(expr); >> : stream.setStreamContext(context); >> : @@ -284,9 +293,9 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : >> : //Test maxDocFreq param >> : String docFreqExpr = "gatherNodes(collection1, " + >> : - "walk=\"product1, product7->product_s\"," + >> : - "maxDocFreq=\"2\","+ >> : - "gather=\"basket_s\")"; >> : + "walk=\"product1, product7->product_s\"," + >> : + "maxDocFreq=\"2\","+ >> : + "gather=\"basket_s\")"; >> : >> : stream = (GatherNodesStream)factory.constructStream(docFreqExpr); >> : stream.setStreamContext(context); >> : @@ -299,9 +308,9 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : >> : >> : String expr2 = "gatherNodes(collection1, " + >> : - expr+","+ >> : - "walk=\"node->basket_s\"," + >> : - "gather=\"product_s\", count(*), >> avg(price_f), sum(price_f), min(price_f), max(price_f))"; >> : + expr+","+ >> : + "walk=\"node->basket_s\"," + >> : + "gather=\"product_s\", count(*), avg(price_f), sum(price_f), >> min(price_f), max(price_f))"; >> : >> : stream = (GatherNodesStream)factory.constructStream(expr2); >> : >> : @@ -338,8 +347,8 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : >> : //Test list of root nodes >> : expr = "gatherNodes(collection1, " + >> : - "walk=\"product4, product7->product_s\"," + >> : - "gather=\"basket_s\")"; >> : + "walk=\"product4, product7->product_s\"," + >> : + "gather=\"basket_s\")"; >> : >> : stream = (GatherNodesStream)factory.constructStream(expr); >> : >> : @@ -356,8 +365,8 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : //Test with negative filter query >> : >> : expr = "gatherNodes(collection1, " + >> : - "walk=\"product4, product7->product_s\"," + >> : - "gather=\"basket_s\", >> fq=\"-basket_s:basket4\")"; >> : + "walk=\"product4, product7->product_s\"," + >> : + "gather=\"basket_s\", fq=\"-basket_s:basket4\")"; >> : >> : stream = (GatherNodesStream)factory.constructStream(expr); >> : >> : @@ -406,8 +415,8 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : .withFunctionName("max", MaxMetric.class); >> : >> : String expr = "gatherNodes(collection1, " + >> : - "walk=\"bill->from_s\"," + >> : - "gather=\"to_s\")"; >> : + "walk=\"bill->from_s\"," + >> : + "gather=\"to_s\")"; >> : >> : stream = (GatherNodesStream)factory.constructStream(expr); >> : stream.setStreamContext(context); >> : @@ -423,9 +432,9 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : //Test scatter branches, leaves and trackTraversal >> : >> : expr = "gatherNodes(collection1, " + >> : - "walk=\"bill->from_s\"," + >> : - "gather=\"to_s\","+ >> : - "scatter=\"branches, leaves\", trackTraversal=\"true\")"; >> : + "walk=\"bill->from_s\"," + >> : + "gather=\"to_s\","+ >> : + "scatter=\"branches, leaves\", trackTraversal=\"true\")"; >> : >> : stream = (GatherNodesStream)factory.constructStream(expr); >> : context = new StreamContext(); >> : @@ -461,9 +470,9 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : // Test query root >> : >> : expr = "gatherNodes(collection1, " + >> : - "search(collection1, q=\"message_t:jim\", fl=\"from_s\", >> sort=\"from_s asc\"),"+ >> : - "walk=\"from_s->from_s\"," + >> : - "gather=\"to_s\")"; >> : + "search(collection1, q=\"message_t:jim\", fl=\"from_s\", >> sort=\"from_s asc\"),"+ >> : + "walk=\"from_s->from_s\"," + >> : + "gather=\"to_s\")"; >> : >> : stream = (GatherNodesStream)factory.constructStream(expr); >> : context = new StreamContext(); >> : @@ -482,9 +491,9 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : // Test query root scatter branches >> : >> : expr = "gatherNodes(collection1, " + >> : - "search(collection1, q=\"message_t:jim\", fl=\"from_s\", >> sort=\"from_s asc\"),"+ >> : - "walk=\"from_s->from_s\"," + >> : - "gather=\"to_s\", scatter=\"branches, leaves\")"; >> : + "search(collection1, q=\"message_t:jim\", fl=\"from_s\", >> sort=\"from_s asc\"),"+ >> : + "walk=\"from_s->from_s\"," + >> : + "gather=\"to_s\", scatter=\"branches, leaves\")"; >> : >> : stream = (GatherNodesStream)factory.constructStream(expr); >> : context = new StreamContext(); >> : @@ -505,14 +514,14 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : assertTrue(tuples.get(3).getLong("level").equals(new Long(1))); >> : >> : expr = "gatherNodes(collection1, " + >> : - "search(collection1, q=\"message_t:jim\", fl=\"from_s\", >> sort=\"from_s asc\"),"+ >> : - "walk=\"from_s->from_s\"," + >> : - "gather=\"to_s\")"; >> : + "search(collection1, q=\"message_t:jim\", fl=\"from_s\", >> sort=\"from_s asc\"),"+ >> : + "walk=\"from_s->from_s\"," + >> : + "gather=\"to_s\")"; >> : >> : String expr2 = "gatherNodes(collection1, " + >> : - expr+","+ >> : - "walk=\"node->from_s\"," + >> : - "gather=\"to_s\")"; >> : + expr+","+ >> : + "walk=\"node->from_s\"," + >> : + "gather=\"to_s\")"; >> : >> : stream = (GatherNodesStream)factory.constructStream(expr2); >> : context = new StreamContext(); >> : @@ -548,14 +557,14 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : >> : >> : expr = "gatherNodes(collection1, " + >> : - "search(collection1, q=\"message_t:jim\", fl=\"from_s\", >> sort=\"from_s asc\"),"+ >> : - "walk=\"from_s->from_s\"," + >> : - "gather=\"to_s\")"; >> : + "search(collection1, q=\"message_t:jim\", fl=\"from_s\", >> sort=\"from_s asc\"),"+ >> : + "walk=\"from_s->from_s\"," + >> : + "gather=\"to_s\")"; >> : >> : expr2 = "gatherNodes(collection1, " + >> : - expr+","+ >> : - "walk=\"node->from_s\"," + >> : - "gather=\"to_s\", scatter=\"branches, leaves\")"; >> : + expr+","+ >> : + "walk=\"node->from_s\"," + >> : + "gather=\"to_s\", scatter=\"branches, leaves\")"; >> : >> : stream = (GatherNodesStream)factory.constructStream(expr2); >> : context = new StreamContext(); >> : @@ -589,14 +598,14 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : .commit(cluster.getSolrClient(), COLLECTION); >> : >> : expr = "gatherNodes(collection1, " + >> : - "search(collection1, q=\"message_t:jim\", fl=\"from_s\", >> sort=\"from_s asc\"),"+ >> : - "walk=\"from_s->from_s\"," + >> : - "gather=\"to_s\", trackTraversal=\"true\")"; >> : + "search(collection1, q=\"message_t:jim\", fl=\"from_s\", >> sort=\"from_s asc\"),"+ >> : + "walk=\"from_s->from_s\"," + >> : + "gather=\"to_s\", trackTraversal=\"true\")"; >> : >> : expr2 = "gatherNodes(collection1, " + >> : - expr+","+ >> : - "walk=\"node->from_s\"," + >> : - "gather=\"to_s\", scatter=\"branches, leaves\", >> trackTraversal=\"true\")"; >> : + expr+","+ >> : + "walk=\"node->from_s\"," + >> : + "gather=\"to_s\", scatter=\"branches, leaves\", >> trackTraversal=\"true\")"; >> : >> : stream = (GatherNodesStream)factory.constructStream(expr2); >> : context = new StreamContext(); >> : @@ -634,6 +643,84 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : >> : } >> : >> : + @Test >> : + public void testGraphHandler() throws Exception { >> : + >> : + >> : + new UpdateRequest() >> : + .add(id, "0", "from_s", "bill", "to_s", "jim", "message_t", >> "Hello jim") >> : + .add(id, "1", "from_s", "bill", "to_s", "sam", "message_t", >> "Hello sam") >> : + .add(id, "2", "from_s", "bill", "to_s", "max", "message_t", >> "Hello max") >> : + .add(id, "3", "from_s", "max", "to_s", "kip", "message_t", >> "Hello kip") >> : + .add(id, "4", "from_s", "sam", "to_s", "steve", "message_t", >> "Hello steve") >> : + .add(id, "5", "from_s", "jim", "to_s", "ann", "message_t", >> "Hello steve") >> : + .commit(cluster.getSolrClient(), COLLECTION); >> : + >> : + commit(); >> : + >> : + List<JettySolrRunner> runners = cluster.getJettySolrRunners(); >> : + JettySolrRunner runner = runners.get(0); >> : + String url = runner.getBaseUrl().toString(); >> : + >> : + HttpSolrClient client = new HttpSolrClient(url); >> : + ModifiableSolrParams params = new ModifiableSolrParams(); >> : + >> : + >> : + String expr = "sort(by=\"node asc\", gatherNodes(collection1, " + >> : + "walk=\"bill->from_s\"," + >> : + "trackTraversal=\"true\"," + >> : + "gather=\"to_s\"))"; >> : + >> : + params.add("expr", expr); >> : + QueryRequest query = new QueryRequest(params); >> : + query.setPath("/collection1/graph"); >> : + >> : + query.setResponseParser(new InputStreamResponseParser("xml")); >> : + query.setMethod(SolrRequest.METHOD.POST); >> : + >> : + NamedList<Object> genericResponse = client.request(query); >> : + >> : + >> : + InputStream stream = (InputStream)genericResponse.get("stream"); >> : + InputStreamReader reader = new InputStreamReader(stream, "UTF-8"); >> : + String xml = readString(reader); >> : + //Validate the nodes >> : + String error = h.validateXPath(xml, >> : + "//graph/node[1][@id ='jim']", >> : + "//graph/node[2][@id ='max']", >> : + "//graph/node[3][@id ='sam']"); >> : + if(error != null) { >> : + throw new Exception(error); >> : + } >> : + //Validate the edges >> : + error = h.validateXPath(xml, >> : + "//graph/edge[1][@source ='bill']", >> : + "//graph/edge[1][@target ='jim']", >> : + "//graph/edge[2][@source ='bill']", >> : + "//graph/edge[2][@target ='max']", >> : + "//graph/edge[3][@source ='bill']", >> : + "//graph/edge[3][@target ='sam']"); >> : + >> : + if(error != null) { >> : + throw new Exception(error); >> : + } >> : + >> : + client.close(); >> : + } >> : + >> : + private String readString(InputStreamReader reader) throws Exception{ >> : + StringBuilder builder = new StringBuilder(); >> : + int c = 0; >> : + while((c = reader.read()) != -1) { >> : + builder.append(((char)c)); >> : + } >> : + >> : + return builder.toString(); >> : + } >> : + >> : + >> : + >> : + >> : protected List<Tuple> getTuples(TupleStream tupleStream) throws >> IOException { >> : tupleStream.open(); >> : List<Tuple> tuples = new ArrayList(); >> : @@ -675,7 +762,9 @@ public class GraphExpressionTest extends >> SolrCloudTestCase { >> : throw new Exception("Longs not equal:"+expected+" : "+actual); >> : } >> : >> : + >> : + >> : return true; >> : } >> : >> : -} >> : +} >> : \ No newline at end of file >> : >> : >> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/be1cb9a1/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/StreamExpressionTest.java >> : ---------------------------------------------------------------------- >> : 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 9a0653a..f0b7b7b 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 >> : @@ -175,7 +175,6 @@ public class StreamExpressionTest extends >> SolrCloudTestCase { >> : assert(tuples.size() == 3); >> : assertOrder(tuples, 0, 3, 4); >> : assertLong(tuples.get(1), "a_i", 3); >> : - >> : } >> : >> : @Test >> : >> : >> >> -Hoss >> http://www.lucidworks.com/ >> >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: [email protected] >> For additional commands, e-mail: [email protected] >> >> >
