diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 7f8ca7e73a0..cd415de25a2 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -82,8 +82,12 @@ Detailed Change List New Features ---------------------- + * SOLR-5130: Implement addReplica Collections API (Noble Paul) +* SOLR-5183: JSON updates now support nested child documents using a + "_childDocument_" object key. (Varun Thacker, hossman) + Bug Fixes ---------------------- diff --git a/solr/core/src/java/org/apache/solr/handler/loader/JsonLoader.java b/solr/core/src/java/org/apache/solr/handler/loader/JsonLoader.java index 3c649a40dd0..948708b5155 100644 --- a/solr/core/src/java/org/apache/solr/handler/loader/JsonLoader.java +++ b/solr/core/src/java/org/apache/solr/handler/loader/JsonLoader.java @@ -53,7 +53,8 @@ import org.slf4j.LoggerFactory; */ public class JsonLoader extends ContentStreamLoader { final static Logger log = LoggerFactory.getLogger( JsonLoader.class ); - + private static final String CHILD_DOC_KEY = "_childDocuments_"; + @Override public String getDefaultWT() { return "json"; @@ -409,35 +410,40 @@ public class JsonLoader extends ContentStreamLoader { +" at ["+parser.getPosition()+"]" ); } } - - + + private SolrInputDocument parseDoc(int ev) throws IOException { assert ev == JSONParser.OBJECT_START; - + SolrInputDocument sdoc = new SolrInputDocument(); for (;;) { - SolrInputField sif = parseField(); - if (sif == null) return sdoc; - // pulling out hte pieces may seem weird, but it's because - // SolrInputDocument.addField will do the right thing - // if the doc already has another value for this field - // (ie: repeating fieldname keys) - sdoc.addField(sif.getName(), sif.getValue(), sif.getBoost()); + ev = parser.nextEvent(); + if (ev == JSONParser.OBJECT_END) { + return sdoc; + } + String fieldName = parser.getString(); + + if(fieldName.equals(JsonLoader.CHILD_DOC_KEY)) { + ev = parser.nextEvent(); + assertEvent(ev, JSONParser.ARRAY_START); + while( (ev = parser.nextEvent()) != JSONParser.ARRAY_END ) { + assertEvent(ev, JSONParser.OBJECT_START); + + sdoc.addChildDocument(parseDoc(ev)); + } + } else { + SolrInputField sif = new SolrInputField(fieldName); + parseFieldValue(sif); + // pulling out the pieces may seem weird, but it's because + // SolrInputDocument.addField will do the right thing + // if the doc already has another value for this field + // (ie: repeating fieldname keys) + sdoc.addField(sif.getName(), sif.getValue(), sif.getBoost()); + } + } } - - private SolrInputField parseField() throws IOException { - int ev = parser.nextEvent(); - if (ev == JSONParser.OBJECT_END) { - return null; - } - - String fieldName = parser.getString(); - SolrInputField sif = new SolrInputField(fieldName); - parseFieldValue(sif); - return sif; - } - + private void parseFieldValue(SolrInputField sif) throws IOException { int ev = parser.nextEvent(); if (ev == JSONParser.OBJECT_START) { diff --git a/solr/core/src/test/org/apache/solr/handler/JsonLoaderTest.java b/solr/core/src/test/org/apache/solr/handler/JsonLoaderTest.java index 301ef72942e..50d0cbc4921 100644 --- a/solr/core/src/test/org/apache/solr/handler/JsonLoaderTest.java +++ b/solr/core/src/test/org/apache/solr/handler/JsonLoaderTest.java @@ -547,5 +547,161 @@ public class JsonLoaderTest extends SolrTestCaseJ4 { req.close(); } + @Test + public void testSimpleChildDocs() throws Exception { + String str = "{\n" + + " \"add\": {\n" + + " \"doc\": {\n" + + " \"id\": \"1\",\n" + + " \"_childDocuments_\": [\n" + + " {\n" + + " \"id\": \"2\"\n" + + " },\n" + + " {\n" + + " \"id\": \"3\",\n" + + " \"foo_i\": [666,777]\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; + checkTwoChildDocs(str); + } + + @Test + public void testDupKeysChildDocs() throws Exception { + String str = "{\n" + + " \"add\": {\n" + + " \"doc\": {\n" + + " \"_childDocuments_\": [\n" + + " {\n" + + " \"id\": \"2\"\n" + + " }\n" + + " ],\n" + + " \"id\": \"1\",\n" + + " \"_childDocuments_\": [\n" + + " {\n" + + " \"id\": \"3\",\n" + + " \"foo_i\": 666,\n" + + " \"foo_i\": 777\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; + checkTwoChildDocs(str); + } + + private void checkTwoChildDocs(String rawJsonStr) throws Exception { + SolrQueryRequest req = req("commit","true"); + SolrQueryResponse rsp = new SolrQueryResponse(); + BufferingRequestProcessor p = new BufferingRequestProcessor(null); + JsonLoader loader = new JsonLoader(); + loader.load(req, rsp, new ContentStreamBase.StringStream(rawJsonStr), p); + + assertEquals( 1, p.addCommands.size() ); + + AddUpdateCommand add = p.addCommands.get(0); + SolrInputDocument d = add.solrDoc; + SolrInputField f = d.getField( "id" ); + assertEquals("1", f.getValue()); + + SolrInputDocument cd = d.getChildDocuments().get(0); + SolrInputField cf = cd.getField( "id" ); + assertEquals("2", cf.getValue()); + + cd = d.getChildDocuments().get(1); + cf = cd.getField( "id" ); + assertEquals("3", cf.getValue()); + cf = cd.getField( "foo_i" ); + assertEquals(2, cf.getValueCount()); + + assertEquals(new Object[] {666L,777L}, cf.getValues().toArray()); + + req.close(); + } + + @Test + public void testEmptyChildDocs() throws Exception { + String str = "{\n" + + " \"add\": {\n" + + " \"doc\": {\n" + + " \"id\": \"1\",\n" + + " \"_childDocuments_\": []\n" + + " }\n" + + " }\n" + + "}"; + SolrQueryRequest req = req("commit","true"); + SolrQueryResponse rsp = new SolrQueryResponse(); + BufferingRequestProcessor p = new BufferingRequestProcessor(null); + JsonLoader loader = new JsonLoader(); + loader.load(req, rsp, new ContentStreamBase.StringStream(str), p); + + assertEquals( 1, p.addCommands.size() ); + + AddUpdateCommand add = p.addCommands.get(0); + SolrInputDocument d = add.solrDoc; + SolrInputField f = d.getField( "id" ); + assertEquals("1", f.getValue()); + List cd = d.getChildDocuments(); + assertNull(cd); + + req.close(); + } + + @Test + public void testGrandChildDocs() throws Exception { + String str = "{\n" + + " \"add\": {\n" + + " \"doc\": {\n" + + " \"id\": \"1\",\n" + + " \"_childDocuments_\": [\n" + + " {\n" + + " \"id\": \"2\",\n" + + " \"_childDocuments_\": [\n" + + " {\n" + + " \"id\": \"4\",\n" + + " \"foo_s\": \"Baz\"\n" + + " }\n" + + " ],\n" + + " \"foo_s\": \"Yaz\"\n" + + " },\n" + + " {\n" + + " \"id\": \"3\",\n" + + " \"foo_s\": \"Bar\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; + + SolrQueryRequest req = req("commit","true"); + SolrQueryResponse rsp = new SolrQueryResponse(); + BufferingRequestProcessor p = new BufferingRequestProcessor(null); + JsonLoader loader = new JsonLoader(); + loader.load(req, rsp, new ContentStreamBase.StringStream(str), p); + + assertEquals( 1, p.addCommands.size() ); + + AddUpdateCommand add = p.addCommands.get(0); + SolrInputDocument one = add.solrDoc; + assertEquals("1", one.getFieldValue("id")); + + SolrInputDocument two = one.getChildDocuments().get(0); + assertEquals("2", two.getFieldValue("id")); + assertEquals("Yaz", two.getFieldValue("foo_s")); + + SolrInputDocument four = two.getChildDocuments().get(0); + assertEquals("4", four.getFieldValue("id")); + assertEquals("Baz", four.getFieldValue("foo_s")); + + SolrInputDocument three = one.getChildDocuments().get(1); + assertEquals("3", three.getFieldValue("id")); + assertEquals("Bar", three.getFieldValue("foo_s")); + + req.close(); + + } + }