SimpleOrderedMap, JSON named list changes: SOLR-125

git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@501512 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yonik Seeley 2007-01-30 18:36:32 +00:00
parent cb9efe43d0
commit b6dd62544d
18 changed files with 186 additions and 66 deletions

View File

@ -72,6 +72,11 @@ Changes in runtime behavior
1. Highlighting using DisMax will only pick up terms from the main
user query, not boost or filter queries (klaas).
2. SOLR-125: Change default of json.nl to flat, change so that
json.nl only affects items where order matters (facet constraint
listings). Fix JSON output bug for null values. Internal JAVA API:
change most uses of NamedList to SimpleOrderedMap. (yonik)
Optimizations
1. SOLR-114: HashDocSet specific implementations of union() and andNot()
for a 20x performance improvement for those set operations, and a new

View File

@ -27,11 +27,7 @@ import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.update.*;
import org.apache.solr.util.DOMUtil;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.RefCounted;
import org.apache.solr.util.StrUtils;
import org.apache.solr.util.XML;
import org.apache.solr.util.*;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@ -607,7 +603,7 @@ public final class SolrCore {
public void execute(SolrRequestHandler handler, SolrQueryRequest req, SolrQueryResponse rsp) {
// setup response header and handle request
final NamedList responseHeader = new NamedList();
final NamedList responseHeader = new SimpleOrderedMap();
rsp.add("responseHeader", responseHeader);
handler.handleRequest(req,rsp);
setResponseHeaderValues(responseHeader,req,rsp);

View File

@ -19,12 +19,14 @@ package org.apache.solr.handler;
import java.io.IOException;
import java.util.Map;
import java.util.ArrayList;
import org.apache.commons.io.IOUtils;
import org.apache.solr.request.ContentStream;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.SimpleOrderedMap;
public class DumpRequestHandler extends RequestHandlerBase
{
@ -36,29 +38,21 @@ public class DumpRequestHandler extends RequestHandlerBase
// Write the streams...
if( req.getContentStreams() != null ) {
NamedList<Object> streams = new NamedList<Object>();
ArrayList streams = new ArrayList();
// Cycle through each stream
for( ContentStream content : req.getContentStreams() ) {
NamedList<Object> stream = new NamedList<Object>();
NamedList<Object> stream = new SimpleOrderedMap<Object>();
stream.add( "name", content.getName() );
stream.add( "fieldName", content.getSourceInfo() );
stream.add( "size", content.getSize() );
stream.add( "contentType", content.getContentType() );
stream.add( "stream", IOUtils.toString( content.getStream() ) );
streams.add( "stream", stream );
streams.add( stream );
}
rsp.add( "streams", streams );
}
// Show the context
Map<Object,Object> context = req.getContext();
if( context != null ) {
NamedList ctx = new NamedList();
for( Map.Entry<Object,Object> entry : context.entrySet() ) {
ctx.add( entry.getKey().toString(), entry.getValue() );
}
rsp.add( "context", ctx );
}
rsp.add("context", req.getContext());
}
//////////////////////// SolrInfoMBeans methods //////////////////////
@ -70,16 +64,16 @@ public class DumpRequestHandler extends RequestHandlerBase
@Override
public String getVersion() {
return "$Revision:$";
return "$Revision$";
}
@Override
public String getSourceId() {
return "$Id:$";
return "$Id$";
}
@Override
public String getSource() {
return "$URL:$";
return "$URL$";
}
}

View File

@ -27,6 +27,7 @@ import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.SolrPluginUtils;
import org.apache.solr.util.SimpleOrderedMap;
/**
*
@ -104,7 +105,7 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
}
public NamedList getStatistics() {
NamedList lst = new NamedList();
NamedList lst = new SimpleOrderedMap();
lst.add("requests", numRequests);
lst.add("errors", numErrors);
return lst;

View File

@ -32,7 +32,6 @@ import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.servlet.SolrServlet;
import org.apache.solr.update.AddUpdateCommand;
import org.apache.solr.update.CommitUpdateCommand;
import org.apache.solr.update.DeleteUpdateCommand;
@ -41,6 +40,7 @@ import org.apache.solr.update.UpdateHandler;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.StrUtils;
import org.apache.solr.util.XML;
import org.apache.solr.util.SimpleOrderedMap;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
@ -113,7 +113,7 @@ public class XmlUpdateRequestHandler extends RequestHandlerBase
UpdateHandler updateHandler = core.getUpdateHandler();
// TODO: What results should be returned?
NamedList res = new NamedList();
SimpleOrderedMap res = new SimpleOrderedMap();
XmlPullParser xpp = factory.newPullParser();
long startTime=System.currentTimeMillis();
@ -384,16 +384,16 @@ public class XmlUpdateRequestHandler extends RequestHandlerBase
@Override
public String getVersion() {
return "$Revision:$";
return "$Revision$";
}
@Override
public String getSourceId() {
return "$Id:$";
return "$Id$";
}
@Override
public String getSource() {
return "$URL:$";
return "$URL$";
}
}

View File

@ -22,6 +22,7 @@ import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrException;
import org.apache.solr.core.SolrInfoMBean;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.SimpleOrderedMap;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.FieldType;
import org.apache.solr.search.SolrIndexSearcher;
@ -105,7 +106,7 @@ public class IndexInfoRequestHandler implements SolrRequestHandler, SolrInfoMBea
}
public NamedList getStatistics() {
return new NamedList();
return new SimpleOrderedMap();
}
}

View File

@ -24,6 +24,7 @@ import org.apache.solr.schema.TextField;
import org.apache.solr.search.DocIterator;
import org.apache.solr.search.DocList;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.SimpleOrderedMap;
import java.io.IOException;
import java.io.Writer;
@ -62,6 +63,7 @@ class JSONWriter extends TextResponseWriter {
private static final String JSON_NL_STYLE="json.nl";
private static final String JSON_NL_MAP="map";
private static final String JSON_NL_FLAT="flat";
private static final String JSON_NL_ARROFARR="arrarr";
private static final String JSON_NL_ARROFMAP="arrmap";
private static final String JSON_WRAPPER_FUNCTION="json.wrf";
@ -69,19 +71,15 @@ class JSONWriter extends TextResponseWriter {
public JSONWriter(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) {
super(writer, req, rsp);
namedListStyle = req.getParam(JSON_NL_STYLE);
namedListStyle = namedListStyle==null ? JSON_NL_MAP : namedListStyle.intern();
wrapperFunction = req.getParam(JSON_WRAPPER_FUNCTION);
namedListStyle = req.getParams().get(JSON_NL_STYLE, JSON_NL_FLAT).intern();
wrapperFunction = req.getParams().get(JSON_WRAPPER_FUNCTION);
}
public void writeResponse() throws IOException {
NamedList nl = new NamedList();
nl.addAll(rsp.getValues());
// give the main response a name it it doesn't have one
if(wrapperFunction!=null) {
writer.write(wrapperFunction + "(");
}
writeNamedList(null, nl);
writeNamedList(null, rsp.getValues());
if(wrapperFunction!=null) {
writer.write(")");
}
@ -92,10 +90,11 @@ class JSONWriter extends TextResponseWriter {
writer.write(':');
}
// Represents a NamedList directly as a JSON Object (essentially a Map)
// more natural but potentially problematic since order is not maintained and keys
// can't be repeated.
protected void writeNamedListAsMap(String name, NamedList val) throws IOException {
/** Represents a NamedList directly as a JSON Object (essentially a Map)
* Map null to "" and name mangle any repeated keys to avoid repeats in the
* output.
*/
protected void writeNamedListAsMapMangled(String name, NamedList val) throws IOException {
int sz = val.size();
writer.write('{');
incLevel();
@ -149,6 +148,31 @@ class JSONWriter extends TextResponseWriter {
writer.write('}');
}
/** Represents a NamedList directly as a JSON Object (essentially a Map)
* repeating any keys if they are repeated in the NamedList. null is mapped
* to "".
*/
protected void writeNamedListAsMapWithDups(String name, NamedList val) throws IOException {
int sz = val.size();
writer.write('{');
incLevel();
for (int i=0; i<sz; i++) {
if (i!=0) {
writer.write(',');
}
String key = val.getName(i);
if (key==null) key="";
indent();
writeKey(key, true);
writeVal(key,val.getVal(i));
}
decLevel();
writer.write('}');
}
// Represents a NamedList directly as an array of JSON objects...
// NamedList("a"=1,"b"=2,null=3) => [{"a":1},{"b":2},3]
protected void writeNamedListAsArrMap(String name, NamedList val) throws IOException {
@ -225,14 +249,42 @@ class JSONWriter extends TextResponseWriter {
writer.write(']');
}
// Represents a NamedList directly as an array with keys/values
// interleaved.
// NamedList("a"=1,"b"=2,null=3) => ["a",1,"b",2,null,3]
protected void writeNamedListAsFlat(String name, NamedList val) throws IOException {
int sz = val.size();
indent();
writer.write('[');
incLevel();
for (int i=0; i<sz; i++) {
if (i!=0) {
writer.write(',');
}
String key = val.getName(i);
indent();
writeStr(null, key, true);
writer.write(',');
writeVal(key, val.getVal(i));
}
decLevel();
writer.write(']');
}
public void writeNamedList(String name, NamedList val) throws IOException {
if (namedListStyle==JSON_NL_ARROFMAP) {
writeNamedListAsArrMap(name,val);
if (val instanceof SimpleOrderedMap) {
writeNamedListAsMapWithDups(name,val);
} else if (namedListStyle==JSON_NL_FLAT) {
writeNamedListAsFlat(name,val);
} else if (namedListStyle==JSON_NL_MAP){
writeNamedListAsMapWithDups(name,val);
} else if (namedListStyle==JSON_NL_ARROFARR) {
writeNamedListAsArrArr(name,val);
} else {
writeNamedListAsMap(name,val);
} else if (namedListStyle==JSON_NL_ARROFMAP) {
writeNamedListAsArrMap(name,val);
}
}
@ -455,7 +507,7 @@ class JSONWriter extends TextResponseWriter {
for (Map.Entry entry : (Set<Map.Entry>)val.entrySet()) {
Object e = entry.getKey();
String k = e==null ? null : e.toString();
String k = e==null ? "" : e.toString();
Object v = entry.getValue();
if (isFirstVal) {
@ -502,7 +554,7 @@ class JSONWriter extends TextResponseWriter {
// Primitive types
//
public void writeNull(String name) throws IOException {
writeStr(name,"null",false);
writer.write("null");
}
public void writeInt(String name, String val) throws IOException {

View File

@ -32,6 +32,7 @@ import org.apache.solr.schema.BoolField;
import org.apache.solr.search.*;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.BoundedTreeSet;
import org.apache.solr.util.SimpleOrderedMap;
import java.io.IOException;
import java.util.Arrays;
@ -76,7 +77,7 @@ public class SimpleFacets {
if (!params.getBool(params.FACET,true))
return null;
NamedList res = new NamedList();
NamedList res = new SimpleOrderedMap();
try {
res.add("facet_queries", getFacetQueryCounts());
@ -98,7 +99,7 @@ public class SimpleFacets {
*/
public NamedList getFacetQueryCounts() throws IOException,ParseException {
NamedList res = new NamedList();
NamedList res = new SimpleOrderedMap();
/* Ignore SolrParams.DF - could have init param facet.query assuming
* the schema default with query param DF intented to only affect Q.
@ -160,7 +161,7 @@ public class SimpleFacets {
public NamedList getFacetFieldCounts()
throws IOException {
NamedList res = new NamedList();
NamedList res = new SimpleOrderedMap();
String[] facetFs = params.getParams(SolrParams.FACET_FIELD);
if (null != facetFs) {
for (String f : facetFs) {

View File

@ -19,6 +19,7 @@ package org.apache.solr.request;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.StrUtils;
import org.apache.solr.util.SimpleOrderedMap;
import javax.servlet.ServletRequest;
@ -266,7 +267,7 @@ public abstract class SolrParams {
/** Convert this to a NamedList */
public NamedList toNamedList() {
final NamedList result = new NamedList();
final SimpleOrderedMap result = new SimpleOrderedMap();
for(Iterator<String> it=getParameterNamesIterator(); it.hasNext(); ) {
final String name = it.next();

View File

@ -18,6 +18,7 @@
package org.apache.solr.request;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.SimpleOrderedMap;
import java.util.*;
@ -60,7 +61,7 @@ public class SolrQueryResponse {
* @see #setAllValues
* @see <a href="#returnable_data">Note on Returnable Data</a>
*/
protected NamedList values = new NamedList();
protected NamedList values = new SimpleOrderedMap();
protected Set<String> defaultReturnFields;

View File

@ -20,6 +20,7 @@ package org.apache.solr.search;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrException;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.SimpleOrderedMap;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
@ -252,7 +253,7 @@ public class LRUCache implements SolrCache {
}
public NamedList getStatistics() {
NamedList lst = new NamedList();
NamedList lst = new SimpleOrderedMap();
synchronized (map) {
lst.add("lookups", lookups);
lst.add("hits", hits);

View File

@ -32,6 +32,7 @@ import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.OpenBitSet;
import org.apache.solr.util.SimpleOrderedMap;
import java.io.IOException;
import java.net.URL;
@ -1434,7 +1435,7 @@ public class SolrIndexSearcher extends Searcher implements SolrInfoMBean {
}
public NamedList getStatistics() {
NamedList lst = new NamedList();
NamedList lst = new SimpleOrderedMap();
lst.add("caching", cachingEnabled);
lst.add("numDocs", reader.numDocs());
lst.add("maxDoc", reader.maxDoc());

View File

@ -38,6 +38,7 @@ import java.net.URL;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.QueryParsing;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.SimpleOrderedMap;
import org.apache.solr.update.UpdateHandler;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrException;
@ -374,7 +375,7 @@ public class DirectUpdateHandler extends UpdateHandler {
}
public NamedList getStatistics() {
NamedList lst = new NamedList();
NamedList lst = new SimpleOrderedMap();
return lst;
}

View File

@ -44,6 +44,7 @@ import java.net.URL;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.QueryParsing;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.SimpleOrderedMap;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrException;
@ -676,7 +677,7 @@ public class DirectUpdateHandler2 extends UpdateHandler {
}
public NamedList getStatistics() {
NamedList lst = new NamedList();
NamedList lst = new SimpleOrderedMap();
lst.add("commits", commitCommands.get());
lst.add("optimizes", optimizeCommands.get());
lst.add("docsPending", numDocsPending.get());

View File

@ -216,7 +216,7 @@ public class HighlightingUtils
return null;
SolrIndexSearcher searcher = req.getSearcher();
NamedList fragments = new NamedList();
NamedList fragments = new SimpleOrderedMap();
String[] fieldNames = getHighlightFields(query, req, defaultFields);
Document[] readDocs = new Document[docs.size()];
{
@ -236,7 +236,7 @@ public class HighlightingUtils
{
int docId = iterator.nextDoc();
Document doc = readDocs[i];
NamedList docSummaries = new NamedList();
NamedList docSummaries = new SimpleOrderedMap();
for (String fieldName : fieldNames)
{
fieldName = fieldName.trim();

View File

@ -35,11 +35,15 @@ import java.io.Serializable;
* </ul>
*
* <p>
* :TODO: In the future, it would be nice if this extended Map or Collection,
* had iterators, used java5 generics, had a faster lookup for
* large lists, etc...
* It could also have an interface, and multiple implementations.
* One might have indexed lookup, one might not.
* A NamedList provides fast access by element number, but not by name.
* </p>
* <p>
* When a NamedList is serialized, order is considered more important than access
* by key, so ResponseWriters that output to a format such as JSON will normally
* choose a data structure that allows order to be easily preserved in various
* clients (i.e. not a straight map).
* If access by key is more important, see {@link SimpleOrderedMap},
* or simply use a regular {@link Map}
* </p>
*
* @author yonik
@ -200,10 +204,10 @@ public class NamedList<T> implements Cloneable, Serializable, Iterable<Map.Entry
/**
* Makes a <i>shallow copy</i> of the named list.
*/
public NamedList clone() {
public NamedList<T> clone() {
ArrayList newList = new ArrayList(nvPairs.size());
newList.addAll(nvPairs);
return new NamedList(newList);
return new NamedList<T>(newList);
}

View File

@ -0,0 +1,60 @@
package org.apache.solr.util;
/**
* 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.util.*;
/** <code>SimpleOrderedMap</code> is a {@link NamedList} where access by key is more
* important than maintaining order when it comes to representing the
* held data in other forms, as ResponseWriters normally do.
* It's normally not a good idea to repeat keys or use null keys, but this
* is not enforced. If key uniqueness enforcement is desired, use a regular {@link Map}.
* <p>
* For example, a JSON response writer may choose to write a SimpleOrderedMap
* as {"foo":10,"bar":20} and may choose to write a NamedList as
* ["foo",10,"bar",20]. An XML response writer may choose to render both
* the same way.
* </p>
* <p>
* This class does not provide efficient lookup by key, it's main purpose is
* to hold data to be serialized. It aims to minimize overhead and to be
* efficient at adding new elements.
* </p>
*/
public class SimpleOrderedMap<T> extends NamedList<T> {
/** Creates an empty instance */
public SimpleOrderedMap() {
super();
}
/**
* Creates an instance backed by an explicitly specified list of
* pairwise names/values.
*
* @param nameValuePairs underlying List which should be used to implement a SimpleOrderedMap; modifying this List will affect the SimpleOrderedMap.
*/
public SimpleOrderedMap(List nameValuePairs) {
super(nameValuePairs);
}
public SimpleOrderedMap<T> clone() {
ArrayList newList = new ArrayList(nvPairs.size());
newList.addAll(nvPairs);
return new SimpleOrderedMap<T>(newList);
}
}

View File

@ -305,7 +305,7 @@ public class SolrPluginUtils {
NamedList dbg = null;
if (debug!=null) {
dbg = new NamedList();
dbg = new SimpleOrderedMap();
/* userQuery may have been pre-processes .. expose that */
dbg.add("rawquerystring", req.getQueryString());
@ -382,7 +382,7 @@ public class SolrPluginUtils {
NamedList dbg = null;
if (debug!=null) {
dbg = new NamedList();
dbg = new SimpleOrderedMap();
/* userQuery may have been pre-processes .. expose that */
dbg.add("rawquerystring", req.getQueryString());
@ -425,7 +425,7 @@ public class SolrPluginUtils {
IndexSchema schema)
throws IOException {
NamedList explainList = new NamedList();
NamedList explainList = new SimpleOrderedMap();
DocIterator iterator = docs.iterator();
for (int i=0; i<docs.size(); i++) {
int id = iterator.nextDoc();