fill in alternate XML/SolrJ examples for existing JSON examples

This commit is contained in:
Chris Hostetter 2020-09-01 15:40:40 -07:00
parent 1ba402b308
commit 5d293276a3
2 changed files with 411 additions and 18 deletions

View File

@ -1,4 +1,6 @@
= Indexing Nested Child Documents
:solr-root-path: ../../
:example-source-dir: {solr-root-path}solrj/src/test/org/apache/solr/client/ref_guide_examples/
// 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
@ -118,18 +120,89 @@ The <<uploading-data-with-index-handlers#json-update-convenience-paths,`/update/
[.tab-label]*XML*
[source,xml]
----
nocommit: TODO: XML equivilent of JSON above
<add>
<doc>
<field name="id">P11!prod</field>
<field name="name_s">Swingline Stapler</field>
<field name="description_t">The Cadillac of office staplers ...</field>
<field name="skus">
<doc>
<field name="id">P11!S21</field>
<field name="color_s">RED</field>
<field name="price_i">42</field>
<field name="manuals">
<doc>
<field name="id">P11!D41</field>
<field name="name_s">Red Swingline Brochure</field>
<field name="pages_i">1</field>
<field name="content_t">...</field>
</doc>
</field>
</doc>
<doc>
<field name="id">P11!S31</field>
<field name="color_s">BLACK</field>
<field name="price_i">3</field>
</doc>
</field>
<field name="manuals">
<doc>
<field name="id">P11!D51</field>
<field name="name_s">Quick Reference Guide</field>
<field name="pages_i">1</field>
<field name="content_t">How to use your stapler ...</field>
</doc>
<doc>
<field name="id">P11!D61</field>
<field name="name_s">Warranty Details</field>
<field name="pages_i">42</field>
<field name="content_t">... lifetime guarantee ...</field>
</doc>
</field>
</doc>
<doc>
<field name="id">P22!prod</field>
<field name="name_s">Mont Blanc Fountain Pen</field>
<field name="description_t">A Premium Writing Instrument ...</field>
<field name="skus">
<doc>
<field name="id">P22!S22</field>
<field name="color_s">RED</field>
<field name="price_i">89</field>
<field name="manuals">
<doc>
<field name="id">P22!D42</field>
<field name="name_s">Red Mont Blanc Brochure</field>
<field name="pages_i">1</field>
<field name="content_t">...</field>
</doc>
</field>
</doc>
<doc>
<field name="id">P22!S32</field>
<field name="color_s">BLACK</field>
<field name="price_i">67</field>
</doc>
</field>
<field name="manuals">
<doc>
<field name="id">P22!D52</field>
<field name="name_s">How To Use A Pen</field>
<field name="pages_i">42</field>
<field name="content_t">Start by removing the cap ...</field>
</doc>
</field>
</doc>
</add>
----
====
[example.tab-pane#solrj]
====
[.tab-label]*SolrJ*
[source,java]
[source,java,indent=0]
----
nocommit: TODO: SolrJ equivilent of JSON above
nocommit: ... do we even have a test proving this works correctly
nocommit: the SolrInputDocument methods for addChildDocument methods still don't take "field name"
include::{example-source-dir}IndexingNestedDocuments.java[tag=nest-path]
----
====
--
@ -168,7 +241,7 @@ There are several additional schema considerations that should be considered for
** If you do not use `\_nest_path_` it is strongly recomended that every document have some field that differentiates root documents from their nested children -- and differentiates different "types" of child documents. This is not strictly neccessary, so long as it's possible to write a "filter" query that can be used to isolate and select only parent documents for use in the <<other-parsers.adoc#block-join-query-parsers,block join query parsers>> and <<searching-nested-documents.adoc#child-doc-transformer,[child]>> doc transformer
* `\_nest_parent_` is an optional field that (if defined) will be populated by Solr automatically to store the `id` of each document's _immediate_ parent document (if there is one).
+
[sourece,xml]
[source,xml]
----
<field name="_nest_parent_" type="string" indexed="true" stored="true" />
----
@ -214,7 +287,7 @@ Although not recommended, it is also possible to index child documents "anonymou
"price_i": 42,
"_childDocuments_": [
{ "id": "P11!D41",
"type_s": "DOC",
"type_s": "MANUAL",
"name_s": "Red Swingline Brochure",
"pages_i":1,
"content_t": "..."
@ -226,13 +299,13 @@ Although not recommended, it is also possible to index child documents "anonymou
"price_i": 3
},
{ "id": "P11!D51",
"type_s": "DOC",
"type_s": "MANUAL",
"name_s": "Quick Reference Guide",
"pages_i":1,
"content_t": "How to use your stapler ..."
},
{ "id": "P11!D61",
"type_s": "DOC",
"type_s": "MANUAL",
"name_s": "Warranty Details",
"pages_i":42,
"content_t": "... lifetime guarantee ..."
@ -247,16 +320,56 @@ Although not recommended, it is also possible to index child documents "anonymou
[.tab-label]*XML*
[source,xml]
----
nocommit: TODO: XML equivilent of JSON above
<add>
<doc>
<field name="id">P11!prod</field>
<field name="type_s">PRODUCT</field>
<field name="name_s">Swingline Stapler</field>
<field name="description_t">The Cadillac of office staplers ...</field>
<doc>
<field name="id">P11!S21</field>
<field name="type_s">SKU</field>
<field name="color_s">RED</field>
<field name="price_i">42</field>
<doc>
<field name="id">P11!D41</field>
<field name="type_s">MANUAL</field>
<field name="name_s">Red Swingline Brochure</field>
<field name="pages_i">1</field>
<field name="content_t">...</field>
</doc>
</doc>
<doc>
<field name="id">P11!S31</field>
<field name="type_s">SKU</field>
<field name="color_s">BLACK</field>
<field name="price_i">3</field>
</doc>
<doc>
<field name="id">P11!D51</field>
<field name="type_s">MANUAL</field>
<field name="name_s">Quick Reference Guide</field>
<field name="pages_i">1</field>
<field name="content_t">How to use your stapler ...</field>
</doc>
<doc>
<field name="id">P11!D61</field>
<field name="type_s">MANUAL</field>
<field name="name_s">Warranty Details</field>
<field name="pages_i">42</field>
<field name="content_t">... lifetime guarantee ...</field>
</doc>
</doc>
</add>
----
====
[example.tab-pane#anon_solrj]
====
[.tab-label]*SolrJ*
[source,java]
[source,java,indent=0]
----
nocommit: TODO: SolrJ equivilent of JSON above
include::{example-source-dir}IndexingNestedDocuments.java[tag=anon-kids]
----
====
@ -290,7 +403,7 @@ $ curl --globoff 'http://localhost:8983/solr/gettingstarted/select?omitHeader=tr
"_childDocuments_":[
{
"id":"P11!D41",
"type_s":"DOC",
"type_s":"MANUAL",
"name_s":"Red Swingline Brochure",
"pages_i":1,
"content_t":"...",
@ -309,14 +422,14 @@ $ curl --globoff 'http://localhost:8983/solr/gettingstarted/select?omitHeader=tr
"_version_":1673055562829398016},
{
"id":"P11!D51",
"type_s":"DOC",
"type_s":"MANUAL",
"name_s":"Quick Reference Guide",
"pages_i":1,
"content_t":"How to use your stapler ...",
"_version_":1673055562829398016},
{
"id":"P11!D61",
"type_s":"DOC",
"type_s":"MANUAL",
"name_s":"Warranty Details",
"pages_i":42,
"content_t":"... lifetime guarantee ...",
@ -343,7 +456,7 @@ $ curl --globoff 'http://localhost:8983/solr/gettingstarted/select?omitHeader=tr
<long name="_version_">1673055562829398016</long>
<doc>
<str name="id">P11!D41</str>
<str name="type_s">DOC</str>
<str name="type_s">MANUAL</str>
<str name="name_s">Red Swingline Brochure</str>
<int name="pages_i">1</int>
<str name="content_t">...</str>
@ -362,14 +475,14 @@ $ curl --globoff 'http://localhost:8983/solr/gettingstarted/select?omitHeader=tr
<long name="_version_">1673055562829398016</long></doc>
<doc>
<str name="id">P11!D51</str>
<str name="type_s">DOC</str>
<str name="type_s">MANUAL</str>
<str name="name_s">Quick Reference Guide</str>
<int name="pages_i">1</int>
<str name="content_t">How to use your stapler ...</str>
<long name="_version_">1673055562829398016</long></doc>
<doc>
<str name="id">P11!D61</str>
<str name="type_s">DOC</str>
<str name="type_s">MANUAL</str>
<str name="name_s">Warranty Details</str>
<int name="pages_i">42</int>
<str name="content_t">... lifetime guarantee ...</str>

View File

@ -0,0 +1,280 @@
/*
* 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.
*/
package org.apache.solr.client.ref_guide_examples;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.util.ExternalPaths;
import org.junit.After;
import org.junit.BeforeClass;
/**
* Example SolrJ usage for indexing nested documents
*
* Snippets surrounded by "tag" and "end" comments are extracted and used in the Solr Reference Guide.
*/
public class IndexingNestedDocuments extends SolrCloudTestCase {
public static final String ANON_KIDS_CONFIG = "anon_kids_configset";
@BeforeClass
public static void setupCluster() throws Exception {
configureCluster(1)
// when indexing 'anonymous' kids, we need a schema that doesn't use _nest_path_ so
// that we can use [child] transformer with a parentFilter...
.addConfig(ANON_KIDS_CONFIG, new File(ExternalPaths.TECHPRODUCTS_CONFIGSET).toPath())
.configure();
}
@After
public void cleanCollections() throws Exception {
cluster.deleteAllCollections();
}
/**
* Syntactic sugar so code snippet doesn't refer to test-framework specific method name
*/
public static SolrClient getSolrClient() {
return cluster.getSolrClient();
}
/**
* Demo of using anonymous children when indexing hierarchical documents.
* This test code is used as an 'include' from the ref-guide
*/
public void testIndexingAnonKids() throws Exception {
final String collection = "test_anon";
CollectionAdminRequest.createCollection(collection, ANON_KIDS_CONFIG, 1, 1).process(cluster.getSolrClient());
cluster.getSolrClient().setDefaultCollection(collection);
//
// DO NOT MODIFY THESE EXAMPLE DOCS WITH OUT MAKING THE SAME CHANGES TO THE JSON AND XML
// EQUIVILENT EXAMPLES IN 'indexing-nested-documents.adoc'
//
// tag::anon-kids[]
final SolrClient client = getSolrClient();
final SolrInputDocument p1 = new SolrInputDocument();
p1.setField("id", "P11!prod");
p1.setField("type_s", "PRODUCT");
p1.setField("name_s", "Swingline Stapler");
p1.setField("description_t", "The Cadillac of office staplers ...");
{
final SolrInputDocument s1 = new SolrInputDocument();
s1.setField("id", "P11!S21");
s1.setField("type_s", "SKU");
s1.setField("color_s", "RED");
s1.setField("price_i", 42);
{
final SolrInputDocument m1 = new SolrInputDocument();
m1.setField("id", "P11!D41");
m1.setField("type_s", "MANUAL");
m1.setField("name_s", "Red Swingline Brochure");
m1.setField("pages_i", 1);
m1.setField("content_t", "...");
s1.addChildDocument(m1);
}
final SolrInputDocument s2 = new SolrInputDocument();
s2.setField("id", "P11!S31");
s2.setField("type_s", "SKU");
s2.setField("color_s", "BLACK");
s2.setField("price_i", 3);
final SolrInputDocument m1 = new SolrInputDocument();
m1.setField("id", "P11!D51");
m1.setField("type_s", "MANUAL");
m1.setField("name_s", "Quick Reference Guide");
m1.setField("pages_i", 1);
m1.setField("content_t", "How to use your stapler ...");
final SolrInputDocument m2 = new SolrInputDocument();
m2.setField("id", "P11!D61");
m2.setField("type_s", "MANUAL");
m2.setField("name_s", "Warranty Details");
m2.setField("pages_i", 42);
m2.setField("content_t", "... lifetime guarantee ...");
p1.addChildDocuments(Arrays.asList(s1, s2, m1, m2));
}
client.add(p1);
// end::anon-kids[]
client.commit();
final SolrDocumentList docs = getSolrClient().query
(new SolrQuery("description_t:Cadillac").set("fl", "*,[child parentFilter='type_s:PRODUCT']")).getResults();
assertEquals(1, docs.getNumFound());
assertEquals("P11!prod", docs.get(0).getFieldValue("id"));
// [child] returns a flat list of all (anon) descendents
assertEquals(5, docs.get(0).getChildDocumentCount());
assertEquals(5, docs.get(0).getChildDocuments().size());
// flat list is depth first...
final SolrDocument red_stapler_brochure = docs.get(0).getChildDocuments().get(0);
assertEquals("P11!D41", red_stapler_brochure.getFieldValue("id"));
final SolrDocument red_stapler = docs.get(0).getChildDocuments().get(1);
assertEquals("P11!S21", red_stapler.getFieldValue("id"));
}
/**
* Demo of using <code>NestPath</code> related psuedo-fields when indexing hierarchical documents.
* This test code is used as an 'include' from the ref-guide
*/
public void testIndexingUsingNestPath() throws Exception {
final String collection = "test_anon";
CollectionAdminRequest.createCollection(collection, 1, 1).process(cluster.getSolrClient());
cluster.getSolrClient().setDefaultCollection(collection);
//
// DO NOT MODIFY THESE EXAMPLE DOCS WITH OUT MAKING THE SAME CHANGES TO THE JSON AND XML
// EQUIVILENT EXAMPLES IN 'indexing-nested-documents.adoc'
//
// tag::nest-path[]
final SolrClient client = getSolrClient();
final SolrInputDocument p1 = new SolrInputDocument();
p1.setField("id", "P11!prod");
p1.setField("name_s", "Swingline Stapler");
p1.setField("description_t", "The Cadillac of office staplers ...");
{
final SolrInputDocument s1 = new SolrInputDocument();
s1.setField("id", "P11!S21");
s1.setField("color_s", "RED");
s1.setField("price_i", 42);
{
final SolrInputDocument m1 = new SolrInputDocument();
m1.setField("id", "P11!D41");
m1.setField("name_s", "Red Swingline Brochure");
m1.setField("pages_i", 1);
m1.setField("content_t", "...");
s1.setField("manuals", m1);
}
final SolrInputDocument s2 = new SolrInputDocument();
s2.setField("id", "P11!S31");
s2.setField("color_s", "BLACK");
s2.setField("price_i", 3);
p1.setField("skus", Arrays.asList(s1, s2));
}
{
final SolrInputDocument m1 = new SolrInputDocument();
m1.setField("id", "P11!D51");
m1.setField("name_s", "Quick Reference Guide");
m1.setField("pages_i", 1);
m1.setField("content_t", "How to use your stapler ...");
final SolrInputDocument m2 = new SolrInputDocument();
m2.setField("id", "P11!D61");
m2.setField("name_s", "Warranty Details");
m2.setField("pages_i", 42);
m2.setField("content_t", "... lifetime guarantee ...");
p1.setField("manuals", Arrays.asList(m1, m2));
}
final SolrInputDocument p2 = new SolrInputDocument();
p2.setField("id", "P22!prod");
p2.setField("name_s", "Mont Blanc Fountain Pen");
p2.setField("description_t", "A Premium Writing Instrument ...");
{
final SolrInputDocument s1 = new SolrInputDocument();
s1.setField("id", "P22!S22");
s1.setField("color_s", "RED");
s1.setField("price_i", 89);
{
final SolrInputDocument m1 = new SolrInputDocument();
m1.setField("id", "P22!D42");
m1.setField("name_s", "Red Mont Blanc Brochure");
m1.setField("pages_i", 1);
m1.setField("content_t", "...");
s1.setField("manuals", m1);
}
final SolrInputDocument s2 = new SolrInputDocument();
s2.setField("id", "P22!S32");
s2.setField("color_s", "BLACK");
s2.setField("price_i", 67);
p2.setField("skus", Arrays.asList(s1, s2));
}
{
final SolrInputDocument m1 = new SolrInputDocument();
m1.setField("id", "P22!D52");
m1.setField("name_s", "How To Use A Pen");
m1.setField("pages_i", 42);
m1.setField("content_t", "Start by removing the cap ...");
p2.setField("manuals", m1);
}
client.add(Arrays.asList(p1, p2));
// end::nest-path[]
client.commit();
// Now a quick sanity check that the nest path is working properly...
final SolrDocumentList docs = getSolrClient().query
(new SolrQuery("description_t:Writing").set("fl", "*,[child]")).getResults();
assertEquals(1, docs.getNumFound());
assertEquals("P22!prod", docs.get(0).getFieldValue("id"));
assertEquals(1, docs.get(0).getFieldValues("manuals").size());
assertEquals(SolrDocument.class, docs.get(0).getFieldValues("manuals").iterator().next().getClass());
assertEquals(2, docs.get(0).getFieldValues("skus").size());
final List<Object> skus = new ArrayList<>(docs.get(0).getFieldValues("skus"));
assertEquals(SolrDocument.class, skus.get(0).getClass());
assertEquals(SolrDocument.class, skus.get(1).getClass());
final SolrDocument red_pen = (SolrDocument) skus.get(0);
assertEquals("P22!S22", red_pen.getFieldValue("id"));
assertEquals(1, red_pen.getFieldValues("manuals").size());
assertEquals(SolrDocument.class, red_pen.getFieldValues("manuals").iterator().next().getClass());
final SolrDocument red_pen_brochure = (SolrDocument) red_pen.getFieldValues("manuals").iterator().next();
assertEquals("P22!D42", red_pen_brochure.getFieldValue("id"));
}
}