From f48d27f241496b30f51764ba58681ce809cea945 Mon Sep 17 00:00:00 2001 From: Joel Bernstein Date: Mon, 3 Mar 2014 15:45:59 +0000 Subject: [PATCH] SOLR-5720: Add ExpandComponent to expand results collapsed by the CollapsingQParserPlugin git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1573589 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/solr/core/SolrCore.java | 3 + .../handler/component/ExpandComponent.java | 337 ++++++++++++++++++ .../handler/component/ResponseBuilder.java | 1 + .../solr/handler/component/SearchHandler.java | 1 + .../solr/search/CollapsingQParserPlugin.java | 5 + .../DistributedExpandComponentTest.java | 189 ++++++++++ .../component/TestExpandComponent.java | 193 ++++++++++ .../client/solrj/response/QueryResponse.java | 12 +- .../solr/common/params/ExpandParams.java | 31 ++ 9 files changed, 771 insertions(+), 1 deletion(-) create mode 100644 solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java create mode 100644 solr/core/src/test/org/apache/solr/handler/component/DistributedExpandComponentTest.java create mode 100644 solr/core/src/test/org/apache/solr/handler/component/TestExpandComponent.java create mode 100644 solr/solrj/src/java/org/apache/solr/common/params/ExpandParams.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 1800c54178d..d1c125b4a6b 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrCore.java +++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java @@ -84,6 +84,7 @@ import org.apache.solr.handler.component.QueryComponent; import org.apache.solr.handler.component.RealTimeGetComponent; import org.apache.solr.handler.component.SearchComponent; import org.apache.solr.handler.component.StatsComponent; +import org.apache.solr.handler.component.ExpandComponent; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.response.BinaryResponseWriter; @@ -1237,6 +1238,8 @@ public final class SolrCore implements SolrInfoMBean { addIfNotPresent(components,DebugComponent.COMPONENT_NAME,DebugComponent.class); addIfNotPresent(components,RealTimeGetComponent.COMPONENT_NAME,RealTimeGetComponent.class); addIfNotPresent(components,AnalyticsComponent.COMPONENT_NAME,AnalyticsComponent.class); + addIfNotPresent(components,ExpandComponent.COMPONENT_NAME,ExpandComponent.class); + return components; } private void addIfNotPresent(Map registry, String name, Class c){ diff --git a/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java b/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java new file mode 100644 index 00000000000..0591c4d0051 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java @@ -0,0 +1,337 @@ +/* + * 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.handler.component; + +import org.apache.lucene.index.AtomicReader; +import org.apache.lucene.index.AtomicReaderContext; +import org.apache.lucene.index.SortedDocValues; +import org.apache.lucene.search.DocIdSetIterator; +import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.Scorer; +import org.apache.lucene.search.Sort; +import org.apache.lucene.search.TopDocs; +import org.apache.lucene.search.FieldCache; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.Collector; +import org.apache.lucene.search.TopDocsCollector; +import org.apache.lucene.search.TopFieldCollector; +import org.apache.lucene.search.TopScoreDocCollector; +import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.CharsRef; +import org.apache.lucene.util.FixedBitSet; +import org.apache.solr.common.SolrDocumentList; +import org.apache.solr.common.params.ShardParams; +import org.apache.solr.search.CollapsingQParserPlugin; +import org.apache.solr.search.DocIterator; +import org.apache.solr.search.DocList; +import org.apache.solr.search.QueryParsing; +import org.apache.solr.schema.FieldType; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.params.ExpandParams; +import org.apache.solr.common.util.NamedList; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.search.DocSlice; +import org.apache.solr.search.SolrIndexSearcher; +import org.apache.solr.util.plugin.PluginInfoInitialized; +import org.apache.solr.util.plugin.SolrCoreAware; +import org.apache.solr.core.PluginInfo; +import org.apache.solr.core.SolrCore; + +import com.carrotsearch.hppc.IntObjectOpenHashMap; +import com.carrotsearch.hppc.IntOpenHashSet; +import com.carrotsearch.hppc.cursors.IntObjectCursor; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; + +/** + * The ExpandComponent is designed to work with the CollapsingPostFilter. + * The CollapsingPostFilter collapses a result set on a field. + *

+ * The ExpandComponent expands the collapsed groups for a single page. + *

+ * http parameters: + *

+ * expand=true
+ * expand.rows=5
+ * expand.sort=field asc|desc + * + **/ + +public class ExpandComponent extends SearchComponent implements PluginInfoInitialized, SolrCoreAware { + public static final String COMPONENT_NAME = "expand"; + private PluginInfo info = PluginInfo.EMPTY_INFO; + + @Override + public void init(PluginInfo info) { + this.info = info; + } + + @Override + public void prepare(ResponseBuilder rb) throws IOException { + if (rb.req.getParams().getBool(ExpandParams.EXPAND,false)) { + rb.doExpand = true; + } + } + @Override + public void inform(SolrCore core) { + + } + + @Override + public void process(ResponseBuilder rb) throws IOException { + + if(!rb.doExpand) { + return; + } + + SolrQueryRequest req = rb.req; + SolrParams params = req.getParams(); + + boolean isShard = params.getBool(ShardParams.IS_SHARD, false); + String ids = params.get(ShardParams.IDS); + + if(ids == null && isShard) { + return; + } + + String field = null; + String sortParam = params.get(ExpandParams.EXPAND_SORT); + int limit = params.getInt(ExpandParams.EXPAND_ROWS, 5); + + Sort sort = null; + + if(sortParam != null) { + sort = QueryParsing.parseSortSpec(sortParam, rb.req).getSort(); + } + + Query query = rb.getQuery(); + List filters = rb.getFilters(); + List newFilters = new ArrayList(); + for(Query q : filters) { + if(!(q instanceof CollapsingQParserPlugin.CollapsingPostFilter)) { + newFilters.add(q); + } else { + CollapsingQParserPlugin.CollapsingPostFilter cp = (CollapsingQParserPlugin.CollapsingPostFilter)q; + field = cp.getField(); + } + } + + if(field == null) { + throw new IOException("Expand field is null."); + } + + SolrIndexSearcher searcher = req.getSearcher(); + AtomicReader reader = searcher.getAtomicReader(); + SortedDocValues values = FieldCache.DEFAULT.getTermsIndex(reader, field); + FixedBitSet groupBits = new FixedBitSet(values.getValueCount()); + DocList docList = rb.getResults().docList; + IntOpenHashSet collapsedSet = new IntOpenHashSet(docList.size()*2); + + DocIterator idit = docList.iterator(); + + while(idit.hasNext()) { + int doc = idit.nextDoc(); + int ord = values.getOrd(doc); + if(ord > -1) { + groupBits.set(ord); + collapsedSet.add(doc); + } + } + + Collector collector = null; + GroupExpandCollector groupExpandCollector = new GroupExpandCollector(values, groupBits, collapsedSet, limit, sort); + SolrIndexSearcher.ProcessedFilter pfilter = searcher.getProcessedFilter(null, newFilters); + if(pfilter.postFilter != null) { + pfilter.postFilter.setLastDelegate(groupExpandCollector); + collector = pfilter.postFilter; + } else { + collector = groupExpandCollector; + } + + searcher.search(query, pfilter.filter, collector); + IntObjectOpenHashMap groups = groupExpandCollector.getGroups(); + Iterator it = groups.iterator(); + Map outMap = new HashMap<>(); + BytesRef bytesRef = new BytesRef(); + CharsRef charsRef = new CharsRef(); + FieldType fieldType = searcher.getSchema().getField(field).getType(); + + while(it.hasNext()) { + IntObjectCursor cursor = it.next(); + int ord = cursor.key; + TopDocsCollector topDocsCollector = (TopDocsCollector)cursor.value; + TopDocs topDocs = topDocsCollector.topDocs(); + ScoreDoc[] scoreDocs = topDocs.scoreDocs; + if(scoreDocs.length > 0) { + int[] docs = new int[scoreDocs.length]; + float[] scores = new float[scoreDocs.length]; + for(int i=0; i>it = ex.entrySet().iterator(); + while(it.hasNext()) { + Map.Entry entry = it.next(); + String name = entry.getKey(); + SolrDocumentList val = entry.getValue(); + expanded.put(name, val); + } + } + } + } + @Override + public void finishStage(ResponseBuilder rb) { + + if(!rb.doExpand) { + return; + } + + if (rb.stage != ResponseBuilder.STAGE_GET_FIELDS) { + return; + } + + Map expanded = (Map)rb.req.getContext().get("expanded"); + if(expanded == null) { + expanded = new HashMap(); + } + + rb.rsp.add("expanded", expanded); + } + + private class GroupExpandCollector extends Collector { + private SortedDocValues docValues; + private IntObjectOpenHashMap groups; + private int docBase; + private FixedBitSet groupBits; + private IntOpenHashSet collapsedSet; + private List collectors; + + public GroupExpandCollector(SortedDocValues docValues, FixedBitSet groupBits, IntOpenHashSet collapsedSet, int limit, Sort sort) throws IOException { + int numGroups = collapsedSet.size(); + groups = new IntObjectOpenHashMap(numGroups*2); + collectors = new ArrayList(); + DocIdSetIterator iterator = groupBits.iterator(); + int group = -1; + while((group = iterator.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) { + Collector collector = (sort == null) ? TopScoreDocCollector.create(limit, true) : TopFieldCollector.create(sort,limit, false, false,false, true); + groups.put(group, collector); + collectors.add(collector); + } + + this.collapsedSet = collapsedSet; + this.groupBits = groupBits; + this.docValues = docValues; + } + + public IntObjectOpenHashMap getGroups() { + return this.groups; + } + + public boolean acceptsDocsOutOfOrder() { + return false; + } + + public void collect(int docId) throws IOException { + int doc = docId+docBase; + int ord = docValues.getOrd(doc); + if(ord > -1 && groupBits.get(ord) && !collapsedSet.contains(doc)) { + Collector c = (Collector)groups.get(ord); + c.collect(docId); + } + } + + public void setNextReader(AtomicReaderContext context) throws IOException { + this.docBase = context.docBase; + for(Collector c : collectors) { + c.setNextReader(context); + } + } + + public void setScorer(Scorer scorer) throws IOException { + for(Collector c : collectors) { + c.setScorer(scorer); + } + } + } + + //////////////////////////////////////////// + /// SolrInfoMBean + //////////////////////////////////////////// + + @Override + public String getDescription() { + return "Expand Component"; + } + + @Override + public String getSource() { + return "$URL: https://svn.apache.org/repos/asf/lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java $"; + } + + @Override + public URL[] getDocs() { + try { + return new URL[]{ + new URL("http://wiki.apache.org/solr/ExpandComponent") + }; + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java b/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java index 3d1e52ee729..ac9bf6f598d 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java +++ b/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java @@ -55,6 +55,7 @@ public class ResponseBuilder public SolrQueryResponse rsp; public boolean doHighlights; public boolean doFacets; + public boolean doExpand; public boolean doStats; public boolean doTerms; diff --git a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java index 75ba9ddbf36..67c55a117f8 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java @@ -72,6 +72,7 @@ public class SearchHandler extends RequestHandlerBase implements SolrCoreAware , names.add( StatsComponent.COMPONENT_NAME ); names.add( DebugComponent.COMPONENT_NAME ); names.add( AnalyticsComponent.COMPONENT_NAME ); + names.add( ExpandComponent.COMPONENT_NAME); return names; } diff --git a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java index c1ad92d8e1a..5ea4950ab9b 100644 --- a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java @@ -140,6 +140,11 @@ public class CollapsingQParserPlugin extends QParserPlugin { public static final int NULL_POLICY_COLLAPSE = 1; public static final int NULL_POLICY_EXPAND = 2; + + public String getField(){ + return this.field; + } + public void setCache(boolean cache) { } diff --git a/solr/core/src/test/org/apache/solr/handler/component/DistributedExpandComponentTest.java b/solr/core/src/test/org/apache/solr/handler/component/DistributedExpandComponentTest.java new file mode 100644 index 00000000000..d328bb82389 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/handler/component/DistributedExpandComponentTest.java @@ -0,0 +1,189 @@ +package org.apache.solr.handler.component; + +/* + * 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 org.apache.solr.BaseDistributedSearchTestCase; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.common.SolrDocument; +import org.apache.solr.common.SolrDocumentList; +import org.apache.solr.common.params.CommonParams; +import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.util.NamedList; +import org.junit.BeforeClass; + +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.Iterator; + +/** + * Test for QueryComponent's distributed querying + * + * @see org.apache.solr.handler.component.QueryComponent + */ +public class DistributedExpandComponentTest extends BaseDistributedSearchTestCase { + + public DistributedExpandComponentTest() { + fixShardCount = true; + shardCount = 3; + stress = 0; + } + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + initCore("solrconfig-collapseqparser.xml", "schema11.xml"); + } + + @Override + public void doTest() throws Exception { + del("*:*"); + + index_specific(0,"id","1", "term_s", "YYYY", "group_s", "group1", "test_ti", "5", "test_tl", "10", "test_tf", "2000"); + index_specific(0,"id","2", "term_s", "YYYY", "group_s", "group1", "test_ti", "50", "test_tl", "100", "test_tf", "200"); + index_specific(1,"id","5", "term_s", "YYYY", "group_s", "group2", "test_ti", "4", "test_tl", "10", "test_tf", "2000"); + index_specific(1,"id","6", "term_s", "YYYY", "group_s", "group2", "test_ti", "10", "test_tl", "100", "test_tf", "200"); + index_specific(0,"id","7", "term_s", "YYYY", "group_s", "group1", "test_ti", "1", "test_tl", "100000", "test_tf", "2000"); + index_specific(1,"id","8", "term_s", "YYYY", "group_s", "group2", "test_ti", "2", "test_tl", "100000", "test_tf", "200"); + index_specific(2,"id","9", "term_s", "YYYY", "group_s", "group3", "test_ti", "1000", "test_tl", "1005", "test_tf", "3000"); + index_specific(2, "id", "10", "term_s", "YYYY", "group_s", "group3", "test_ti", "1500", "test_tl", "1001", "test_tf", "3200"); + index_specific(2,"id", "11", "term_s", "YYYY", "group_s", "group3", "test_ti", "1300", "test_tl", "1002", "test_tf", "3300"); + index_specific(1,"id","12", "term_s", "YYYY", "group_s", "group4", "test_ti", "15", "test_tl", "10", "test_tf", "2000"); + index_specific(1,"id","13", "term_s", "YYYY", "group_s", "group4", "test_ti", "16", "test_tl", "9", "test_tf", "2000"); + index_specific(1,"id","14", "term_s", "YYYY", "group_s", "group4", "test_ti", "1", "test_tl", "20", "test_tf", "2000"); + + + commit(); + + + handle.put("explain", SKIPVAL); + handle.put("QTime", SKIPVAL); + handle.put("timestamp", SKIPVAL); + handle.put("score", SKIPVAL); + handle.put("wt", SKIP); + handle.put("distrib", SKIP); + handle.put("shards.qt", SKIP); + handle.put("shards", SKIP); + handle.put("q", SKIP); + handle.put("maxScore", SKIPVAL); + handle.put("_version_", SKIP); + + query("q", "*:*", "fq", "{!collapse field=group_s}", "defType", "edismax", "bf", "field(test_ti)", "expand", "true", "fl","*,score"); + query("q", "*:*", "fq", "{!collapse field=group_s}", "defType", "edismax", "bf", "field(test_ti)", "expand", "true", "expand.sort", "test_tl desc", "fl","*,score"); + query("q", "*:*", "fq", "{!collapse field=group_s}", "defType", "edismax", "bf", "field(test_ti)", "expand", "true", "expand.sort", "test_tl desc", "expand.rows", "1", "fl","*,score"); + //Test no expand results + query("q", "test_ti:5", "fq", "{!collapse field=group_s}", "defType", "edismax", "bf", "field(test_ti)", "expand", "true", "expand.sort", "test_tl desc", "expand.rows", "1", "fl","*,score"); + //Test zero results + query("q", "test_ti:5434343", "fq", "{!collapse field=group_s}", "defType", "edismax", "bf", "field(test_ti)", "expand", "true", "expand.sort", "test_tl desc", "expand.rows", "1", "fl","*,score"); + + //First basic test case. + ModifiableSolrParams params = new ModifiableSolrParams(); + params.add("q", "*:*"); + params.add("fq", "{!collapse field=group_s}"); + params.add("defType", "edismax"); + params.add("bf", "field(test_ti)"); + params.add("expand", "true"); + + setDistributedParams(params); + QueryResponse rsp = queryServer(params); + Map results = rsp.getExpandedResults(); + assertExpandGroups(results, "group1","group2", "group3", "group4"); + assertExpandGroupCountAndOrder("group1", 2, results, "1.0", "7.0"); + assertExpandGroupCountAndOrder("group2", 2, results, "5.0", "8.0"); + assertExpandGroupCountAndOrder("group3", 2, results, "11.0", "9.0"); + assertExpandGroupCountAndOrder("group4", 2, results, "12.0", "14.0"); + + + //Test expand.sort + + params = new ModifiableSolrParams(); + params.add("q", "*:*"); + params.add("fq", "{!collapse field=group_s}"); + params.add("defType", "edismax"); + params.add("bf", "field(test_ti)"); + params.add("expand", "true"); + params.add("expand.sort", "test_tl desc"); + setDistributedParams(params); + rsp = queryServer(params); + results = rsp.getExpandedResults(); + assertExpandGroups(results, "group1","group2", "group3", "group4"); + assertExpandGroupCountAndOrder("group1", 2, results, "7.0", "1.0"); + assertExpandGroupCountAndOrder("group2", 2, results, "8.0", "5.0"); + assertExpandGroupCountAndOrder("group3", 2, results, "9.0", "11.0"); + assertExpandGroupCountAndOrder("group4", 2, results, "14.0", "12.0"); + + + //Test expand.rows + + params = new ModifiableSolrParams(); + params.add("q", "*:*"); + params.add("fq", "{!collapse field=group_s}"); + params.add("defType", "edismax"); + params.add("bf", "field(test_ti)"); + params.add("expand", "true"); + params.add("expand.sort", "test_tl desc"); + params.add("expand.rows", "1"); + setDistributedParams(params); + rsp = queryServer(params); + results = rsp.getExpandedResults(); + assertExpandGroups(results, "group1","group2", "group3", "group4"); + assertExpandGroupCountAndOrder("group1", 1, results, "7.0"); + assertExpandGroupCountAndOrder("group2", 1, results, "8.0"); + assertExpandGroupCountAndOrder("group3", 1, results, "9.0"); + assertExpandGroupCountAndOrder("group4", 1, results, "14.0"); + + } + + private void assertExpandGroups(Map expandedResults, String... groups) throws Exception { + for(int i=0; i groups) { + StringBuilder buf = new StringBuilder(); + Iterator it = groups.keySet().iterator(); + while(it.hasNext()) { + String group = it.next(); + buf.append(group); + if(it.hasNext()) { + buf.append(","); + } + } + return buf.toString(); + } + + private void assertExpandGroupCountAndOrder(String group, int count, MapexpandedResults, String... docs) throws Exception { + SolrDocumentList results = expandedResults.get(group); + if(results == null) { + throw new Exception("Group Not Found:"+group); + } + + if(results.size() != count) { + throw new Exception("Expected Count "+results.size()+" Not Found:"+count); + } + + for(int i=0; i _groupedInfo = null; private GroupResponse _groupResponse = null; + private NamedList _expandedInfo = null; + private Map _expandedResults = null; + // Facet stuff private Map _facetQuery = null; private List _facetFields = null; @@ -119,7 +122,10 @@ public class QueryResponse extends SolrResponseBase _groupedInfo = (NamedList) res.getVal( i ); extractGroupedInfo( _groupedInfo ); } - else if( "highlighting".equals( n ) ) { + else if("expanded".equals(n)) { + _expandedResults = (Map) res.getVal( i ); + } + else if( "highlighting".equals( n ) ) { _highlightingInfo = (NamedList) res.getVal( i ); extractHighlightingInfo( _highlightingInfo ); } @@ -410,6 +416,10 @@ public class QueryResponse extends SolrResponseBase return _facetQuery; } + public Map getExpandedResults(){ + return this._expandedResults; + } + /** * Returns the {@link GroupResponse} containing the group commands. * A group command can be the result of one of the following parameters: diff --git a/solr/solrj/src/java/org/apache/solr/common/params/ExpandParams.java b/solr/solrj/src/java/org/apache/solr/common/params/ExpandParams.java new file mode 100644 index 00000000000..55f37335c15 --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/common/params/ExpandParams.java @@ -0,0 +1,31 @@ +/* + * 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.common.params; + +/** + * Expand parameters + */ +public interface ExpandParams { + + public static final String EXPAND = "expand"; + public static final String EXPAND_SORT = EXPAND + ".sort"; + public static final String EXPAND_ROWS = EXPAND + ".rows"; + + +} +