/* * 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.response.transform; import org.apache.lucene.util.TestUtil; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.SolrInputDocument; import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; public class TestChildDocTransformer extends SolrTestCaseJ4 { private static String ID_FIELD = "id"; private String[] titleVals = new String[2]; @BeforeClass public static void beforeClass() throws Exception { initCore("solrconfig.xml","schema.xml"); } @After public void cleanup() throws Exception { assertU(delQ("*:*")); assertU(commit()); } @Test public void testParentFilter() throws Exception { for(int i=0; i<titleVals.length; i++) { titleVals[i] = TestUtil.randomSimpleString(random(), 1, 20); } createIndex(titleVals); testParentFilterJSON(); testParentFilterXML(); testSubQueryParentFilterJSON(); testSubQueryParentFilterXML(); } @Test public void testAllParams() throws Exception { createSimpleIndex(); testChildDoctransformerJSON(); testChildDoctransformerXML(); testSubQueryXML(); testSubQueryJSON(); } private void testChildDoctransformerXML() { String test1[] = new String[] { "//*[@numFound='1']", "/response/result/doc[1]/doc[1]/int[@name='id']='2'" , "/response/result/doc[1]/doc[2]/int[@name='id']='3'" , "/response/result/doc[1]/doc[3]/int[@name='id']='4'" , "/response/result/doc[1]/doc[4]/int[@name='id']='5'" , "/response/result/doc[1]/doc[5]/int[@name='id']='6'" , "/response/result/doc[1]/doc[6]/int[@name='id']='7'"}; String test2[] = new String[] { "//*[@numFound='1']", "/response/result/doc[1]/doc[1]/int[@name='id']='2'" , "/response/result/doc[1]/doc[2]/int[@name='id']='4'" , "/response/result/doc[1]/doc[3]/int[@name='id']='6'" }; String test3[] = new String[] { "//*[@numFound='1']", "/response/result/doc[1]/doc[1]/int[@name='id']='3'" , "/response/result/doc[1]/doc[2]/int[@name='id']='5'" }; assertQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "*,[child parentFilter=\"subject:parentDocument\"]"), test1); assertQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "subject,[child parentFilter=\"subject:parentDocument\" childFilter=\"title:foo\"]"), test2); assertQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "subject,[child parentFilter=\"subject:parentDocument\" childFilter=\"title:bar\" limit=2]"), test3); } private void testSubQueryXML() { String test1[]; { final String subqueryPath = "/result[@name='children'][@numFound='6']"; test1 = new String[] { "//*[@numFound='1']", "/response/result/doc[1]" + subqueryPath + "/doc[1]/int[@name='id']='2'" , "/response/result/doc[1]" + subqueryPath + "/doc[2]/int[@name='id']='3'" , "/response/result/doc[1]" + subqueryPath + "/doc[3]/int[@name='id']='4'" , "/response/result/doc[1]" + subqueryPath + "/doc[4]/int[@name='id']='5'" , "/response/result/doc[1]" + subqueryPath + "/doc[5]/int[@name='id']='6'" , "/response/result/doc[1]" + subqueryPath + "/doc[6]/int[@name='id']='7'"}; } assertQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "*,children:[subquery]", "children.q","{!child of=subject:parentDocument}{!terms f=id v=$row.id}", "children.rows","10"), test1); String test2[] = new String[] { "//*[@numFound='1']", "/response/result/doc[1]/result[@name='children'][@numFound='3']/doc[1]/int[@name='id']='2'" , "/response/result/doc[1]/result[@name='children'][@numFound='3']/doc[2]/int[@name='id']='4'" , "/response/result/doc[1]/result[@name='children'][@numFound='3']/doc[3]/int[@name='id']='6'" }; assertQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "*,children:[subquery]", "children.q","{!child of=subject:parentDocument}{!terms f=id v=$row.id}", "children.rows","10", "children.fq","title:foo" ), test2); String test3[] = new String[] { "//*[@numFound='1']", "/response/result/doc[1]/result[@name='children'][@numFound='3']/doc[1]/int[@name='id']='3'" , "/response/result/doc[1]/result[@name='children'][@numFound='3']/doc[2]/int[@name='id']='5'" }; assertQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "*,children:[subquery]", "children.q","{!child of=subject:parentDocument}{!terms f=id v=$row.id}", "children.rows","2", "children.fq","title:bar", "children.sort","_docid_ asc" ), test3); } private void testSubQueryJSON() throws Exception { String[] test1 = new String[] { "/response/docs/[0]/children/docs/[0]/id==2", "/response/docs/[0]/children/docs/[1]/id==3", "/response/docs/[0]/children/docs/[2]/id==4", "/response/docs/[0]/children/docs/[3]/id==5", "/response/docs/[0]/children/docs/[4]/id==6", "/response/docs/[0]/children/docs/[5]/id==7" }; String[] test2 = new String[] { "/response/docs/[0]/children/docs/[0]/id==2", "/response/docs/[0]/children/docs/[1]/id==4", "/response/docs/[0]/children/docs/[2]/id==6" }; String[] test3 = new String[] { "/response/docs/[0]/children/docs/[0]/id==3", "/response/docs/[0]/children/docs/[1]/id==5" }; assertJQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "*,children:[subquery]", "children.q","{!child of=subject:parentDocument}{!terms f=id v=$row.id}", "children.rows","10"), test1); assertJQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "*,children:[subquery]", "children.q","{!child of=subject:parentDocument}{!terms f=id v=$row.id}", "children.rows","10", "children.fq","title:foo"), test2); assertJQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "*,children:[subquery]", "children.q","{!child of=subject:parentDocument}{!terms f=id v=$row.id}", "children.rows","2", "children.fq","title:bar", "children.sort","_docid_ asc"), test3); } private void testChildDoctransformerJSON() throws Exception { String[] test1 = new String[] { "/response/docs/[0]/_childDocuments_/[0]/id==2", "/response/docs/[0]/_childDocuments_/[1]/id==3", "/response/docs/[0]/_childDocuments_/[2]/id==4", "/response/docs/[0]/_childDocuments_/[3]/id==5", "/response/docs/[0]/_childDocuments_/[4]/id==6", "/response/docs/[0]/_childDocuments_/[5]/id==7" }; String[] test2 = new String[] { "/response/docs/[0]/_childDocuments_/[0]/id==2", "/response/docs/[0]/_childDocuments_/[1]/id==4", "/response/docs/[0]/_childDocuments_/[2]/id==6" }; String[] test3 = new String[] { "/response/docs/[0]/_childDocuments_/[0]/id==3", "/response/docs/[0]/_childDocuments_/[1]/id==5" }; assertJQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "*,[child parentFilter=\"subject:parentDocument\"]"), test1); assertJQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "subject,[child parentFilter=\"subject:parentDocument\" childFilter=\"title:foo\"]"), test2); assertJQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "subject,[child parentFilter=\"subject:parentDocument\" childFilter=\"title:bar\" limit=2]"), test3); } private void createSimpleIndex() { SolrInputDocument parentDocument = new SolrInputDocument(); parentDocument.addField(ID_FIELD, "1"); parentDocument.addField("subject", "parentDocument"); for(int i=0; i< 6; i++) { SolrInputDocument childDocument = new SolrInputDocument(); childDocument.addField(ID_FIELD, Integer.toString(i+2)); if(i%2==0) { childDocument.addField("title", "foo"); } else { childDocument.addField("title", "bar"); } parentDocument.addChildDocument(childDocument); } try { Long version = addAndGetVersion(parentDocument, null); assertNotNull(version); } catch (Exception e) { fail("Failed to add document to the index"); } assertU(commit()); assertQ(req("q", "*:*"), "//*[@numFound='" + 7 + "']"); } private static void createIndex(String[] titleVals) { String[] parentIDS = new String[] {"1", "4"}; String[] childDocIDS = new String[] {"2", "5"}; String[] grandChildIDS = new String[] {"3", "6"}; for(int i=0; i< parentIDS.length; i++) { SolrInputDocument parentDocument = new SolrInputDocument(); parentDocument.addField(ID_FIELD, parentIDS[i]); parentDocument.addField("subject", "parentDocument"); parentDocument.addField("title", titleVals[i]); SolrInputDocument childDocument = new SolrInputDocument(); childDocument.addField(ID_FIELD, childDocIDS[i]); childDocument.addField("cat", "childDocument"); childDocument.addField("title", titleVals[i]); SolrInputDocument grandChildDocument = new SolrInputDocument(); grandChildDocument.addField(ID_FIELD, grandChildIDS[i]); childDocument.addChildDocument(grandChildDocument); parentDocument.addChildDocument(childDocument); try { Long version = addAndGetVersion(parentDocument, null); assertNotNull(version); } catch (Exception e) { fail("Failed to add document to the index"); } if (random().nextBoolean()) { assertU(commit()); } } assertU(commit()); assertQ(req("q", "*:*"), "//*[@numFound='" + (parentIDS.length + childDocIDS.length + grandChildIDS.length) + "']"); } private void testParentFilterJSON() throws Exception { String[] tests = new String[] { "/response/docs/[0]/id==1", "/response/docs/[0]/_childDocuments_/[0]/id==2", "/response/docs/[0]/_childDocuments_/[0]/cat/[0]/=='childDocument'", "/response/docs/[0]/_childDocuments_/[0]/title/[0]/=='" + titleVals[0] + "'", "/response/docs/[1]/id==4", "/response/docs/[1]/_childDocuments_/[0]/id==5", "/response/docs/[1]/_childDocuments_/[0]/cat/[0]/=='childDocument'", "/response/docs/[1]/_childDocuments_/[0]/title/[0]/=='" + titleVals[1] + "'" }; assertJQ(req("q", "*:*", "sort", "id asc", "fq", "subject:\"parentDocument\" ", "fl", "*,[child childFilter='cat:childDocument' parentFilter=\"subject:parentDocument\"]"), tests); assertJQ(req("q", "*:*", "sort", "id asc", "fq", "subject:\"parentDocument\" ", "fl", "id,[child childFilter='cat:childDocument' parentFilter=\"subject:parentDocument\"]"), tests); } private void testSubQueryParentFilterJSON() throws Exception { String[] tests = new String[] { "/response/docs/[0]/id==1", "/response/docs/[0]/children/docs/[0]/id==2", "/response/docs/[0]/children/docs/[0]/cat/[0]/=='childDocument'", "/response/docs/[0]/children/docs/[0]/title/[0]/=='" + titleVals[0] + "'", "/response/docs/[1]/id==4", "/response/docs/[1]/children/docs/[0]/id==5", "/response/docs/[1]/children/docs/[0]/cat/[0]/=='childDocument'", "/response/docs/[1]/children/docs/[0]/title/[0]/=='" + titleVals[1] + "'" }; assertJQ(req( "q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "*,children:[subquery]", "sort", "id asc", "children.q","{!child of=subject:parentDocument}{!terms f=id v=$row.id}", "children.fq","cat:childDocument", "children.sort","_docid_ asc"), tests); assertJQ(req( "q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "id,children:[subquery]", "sort", "id asc", "children.q","{!child of=subject:parentDocument}{!terms f=id v=$row.id}", "children.fq","cat:childDocument", "children.sort","_docid_ asc"), tests); } private void testParentFilterXML() { String tests[] = new String[] { "//*[@numFound='2']", "/response/result/doc[1]/int[@name='id']='1'" , "/response/result/doc[1]/doc[1]/int[@name='id']='2'" , "/response/result/doc[1]/doc[1]/arr[@name='cat']/str[1]='childDocument'" , "/response/result/doc[1]/doc[1]/arr[@name='title']/str[1]='" + titleVals[0] + "'" , "/response/result/doc[2]/int[@name='id']='4'" , "/response/result/doc[2]/doc[1]/int[@name='id']='5'", "/response/result/doc[2]/doc[1]/arr[@name='cat']/str[1]='childDocument'", "/response/result/doc[2]/doc[1]/arr[@name='title']/str[1]='" + titleVals[1] + "'"}; assertQ(req("q", "*:*", "sort", "id asc", "fq", "subject:\"parentDocument\" ", "fl", "*,[child childFilter='cat:childDocument' parentFilter=\"subject:parentDocument\"]"), tests); assertQ(req("q", "*:*", "sort", "id asc", "fq", "subject:\"parentDocument\" ", "fl", "id,[child childFilter='cat:childDocument' parentFilter=\"subject:parentDocument\"]"), tests); } private void testSubQueryParentFilterXML() { String tests[] = new String[] { "//*[@numFound='2']", "/response/result/doc[1]/int[@name='id']='1'" , "/response/result/doc[1]/result[@name='children'][@numFound=1]/doc[1]/int[@name='id']='2'" , "/response/result/doc[1]/result[@name='children'][@numFound=1]/doc[1]/arr[@name='cat']/str[1]='childDocument'" , "/response/result/doc[1]/result[@name='children'][@numFound=1]/doc[1]/arr[@name='title']/str[1]='" + titleVals[0] + "'" , "/response/result/doc[2]/int[@name='id']='4'" , "/response/result/doc[2]/result[@name='children'][@numFound=1]/doc[1]/int[@name='id']='5'", "/response/result/doc[2]/result[@name='children'][@numFound=1]/doc[1]/arr[@name='cat']/str[1]='childDocument'", "/response/result/doc[2]/result[@name='children'][@numFound=1]/doc[1]/arr[@name='title']/str[1]='" + titleVals[1] + "'"}; assertQ(req( "q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "*,children:[subquery]", "sort", "id asc", "children.q","{!child of=subject:parentDocument}{!terms f=id v=$row.id}", "children.fq","cat:childDocument", "children.sort","_docid_ asc" ), tests); assertQ(req("q", "*:*", "fq", "subject:\"parentDocument\" ", "fl", "id,children:[subquery]", "sort", "id asc", "children.q","{!child of=subject:parentDocument}{!terms f=id v=$row.id}", "children.fq","cat:childDocument", "children.sort","_docid_ asc"), tests); } }