diff --git a/CHANGES.txt b/CHANGES.txt index 7f73b393a45..23783f7e520 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -131,6 +131,11 @@ New Features sqrt, abs, scale, map. Constants may now be used as a value source. (yonik) +25. SOLR-359: Add field type className to Luke response, and enabled access + to the detailed field information from the solrj client API. + (Grant Ingersoll via ehatcher) + + Changes in runtime behavior Optimizations diff --git a/client/java/solrj/src/org/apache/solr/client/solrj/response/LukeResponse.java b/client/java/solrj/src/org/apache/solr/client/solrj/response/LukeResponse.java index f059b429434..a637bf2ff9c 100644 --- a/client/java/solrj/src/org/apache/solr/client/solrj/response/LukeResponse.java +++ b/client/java/solrj/src/org/apache/solr/client/solrj/response/LukeResponse.java @@ -17,147 +17,233 @@ package org.apache.solr.client.solrj.response; -import java.util.HashMap; -import java.util.Map; - +import org.apache.solr.common.luke.FieldFlag; import org.apache.solr.common.util.NamedList; +import java.util.*; + /** * This is an incomplete representation of the data returned from Luke - * + * + * + * * @version $Id$ * @since solr 1.3 */ -public class LukeResponse extends SolrResponseBase -{ - public static class FieldInfo { +public class LukeResponse extends SolrResponseBase { + + public static class FieldTypeInfo { String name; - String type; - String schema; - int docs; - int distinct; - boolean cacheableFaceting; - NamedList topTerms; - - public FieldInfo( String n ) - { - name = n; - } - - @SuppressWarnings("unchecked") - public void read( NamedList nl ) - { - for( Map.Entry entry : nl ) { - if( "type".equals( entry.getKey() ) ) { - type = (String)entry.getValue(); - } - else if( "schema".equals( entry.getKey() ) ) { - schema = (String)entry.getValue(); - } - else if( "docs".equals( entry.getKey() ) ) { - docs = (Integer)entry.getValue(); - } - else if( "distinct".equals( entry.getKey() ) ) { - distinct = (Integer)entry.getValue(); - } - else if( "cacheableFaceting".equals( entry.getKey() ) ) { - cacheableFaceting = (Boolean)entry.getValue(); - } - else if( "topTerms".equals( entry.getKey() ) ) { - topTerms = (NamedList)entry.getValue(); - } - } + String className; + boolean tokenized; + String analyzer; + List fields; + + + public FieldTypeInfo(String name) { + this.name = name; + fields = Collections.emptyList(); } - public boolean isCacheableFaceting() { - return cacheableFaceting; + + public String getAnalyzer() { + return analyzer; } - public int getDistinct() { - return distinct; + public String getClassName() { + return className; } - public int getDocs() { - return docs; + public List getFields() { + return fields; } public String getName() { return name; } - public String getSchema() { - return schema; + public boolean isTokenized() { + return tokenized; + }/* + Sample: + types={ignored={fields=null,tokenized=false,analyzer=org.apache.solr.schema.FieldType$DefaultAnalyzer@f94934}, + integer={fields=null,tokenized=false,analyzer=org.apache.solr.schema.FieldType$DefaultAnalyzer@3525a2}, + sfloat={fields=[price, weight],tokenized=false,analyzer=org.apache.solr.schema.FieldType$DefaultAnalyzer@39cf9c}, + text_ws={fields=[cat],tokenized=true,analyzer=TokenizerChain(org.apache.solr.analysis.WhitespaceTokenizerFactory@6d3ca2)}, + alphaOnlySort={fields=[alphaNameSort],tokenized=true,analyzer=TokenizerChain(org.apache.solr.analysis.KeywordTokenizerFactory@a7bd3b, + org.apache.solr.analysis.LowerCaseFilterFactory@78aae2, org.apache.solr.analysis.TrimFilterFactory@1b16a7, + org.apache.solr.analysis.PatternReplaceFilterFactory@6c6b08)},date={fields=[timestamp],tokenized=false, + analyzer=org.apache.solr.schema.FieldType$DefaultAnalyzer@e6e42e},sint={fields=[popularity], + tokenized=false,analyzer=org.apache.solr.schema.FieldType$DefaultAnalyzer@8ea21d}, + boolean={fields=[inStock],tokenized=false,analyzer=org.apache.solr.schema.BoolField$1@354949}, + textTight={fields=[sku],tokenized=true,analyzer=TokenizerChain(org.apache.solr.analysis.WhitespaceTokenizerFactory@5e88f7, + org.apache.solr.analysis.SynonymFilterFactory@723646, org.apache.solr.analysis.StopFilterFactory@492ff1, + org.apache.solr.analysis.WordDelimiterFilterFactory@eaabad, org.apache.solr.analysis.LowerCaseFilterFactory@ad1355, + org.apache.solr.analysis.EnglishPorterFilterFactory@d03a00, org.apache.solr.analysis.RemoveDuplicatesTokenFilterFactory@900079)}, + long={fields=null,tokenized=false,analyzer=org.apache.solr.schema.FieldType$DefaultAnalyzer@f3b83}, + double={fields=null,tokenized=false,analyzer=org.apache.solr.schema.FieldType$DefaultAnalyzer@c2b07}, + + */ + + @SuppressWarnings("unchecked") + public void read(NamedList nl) { + for (Map.Entry entry : nl) { + String key = entry.getKey(); + if ("fields".equals(key) && entry.getValue() != null) { + List theFields = (List) entry.getValue(); + fields = new ArrayList(theFields); + } else if ("tokenized".equals(key) == true) { + tokenized = Boolean.parseBoolean(entry.getValue().toString()); + } else if ("analyzer".equals(key) == true) { + analyzer = entry.getValue().toString(); + } else if ("className".equals(key) == true) { + className = entry.getValue().toString(); + } + } + } + } + + public static class FieldInfo { + String name; + String type; + String schema; + int docs; + int distinct; + EnumSet flags; + boolean cacheableFaceting; + NamedList topTerms; + + public FieldInfo(String n) { + name = n; } - public NamedList getTopTerms() { - return topTerms; + + @SuppressWarnings("unchecked") + public void read(NamedList nl) { + for (Map.Entry entry : nl) { + if ("type".equals(entry.getKey())) { + type = (String) entry.getValue(); + } + if ("flags".equals(entry.getKey())) { + flags = parseFlags((String) entry.getValue()); + } else if ("schema".equals(entry.getKey())) { + schema = (String) entry.getValue(); + } else if ("docs".equals(entry.getKey())) { + docs = (Integer) entry.getValue(); + } else if ("distinct".equals(entry.getKey())) { + distinct = (Integer) entry.getValue(); + } else if ("cacheableFaceting".equals(entry.getKey())) { + cacheableFaceting = (Boolean) entry.getValue(); + } else if ("topTerms".equals(entry.getKey())) { + topTerms = (NamedList) entry.getValue(); + } + } + } + + public static EnumSet parseFlags(String flagStr) { + EnumSet result = EnumSet.noneOf(FieldFlag.class); + char[] chars = flagStr.toCharArray(); + for (int i = 0; i < chars.length; i++) { + if (chars[i] != '-') { + FieldFlag flag = FieldFlag.getFlag(chars[i]); + result.add(flag); + } + } + return result; + } + + + public EnumSet getFlags() { + return flags; + } + + public boolean isCacheableFaceting() { + return cacheableFaceting; } public String getType() { return type; } - }; + } private NamedList indexInfo; - private Map fieldInfo; - + private Map fieldInfo; + private Map fieldTypeInfo; + @SuppressWarnings("unchecked") public LukeResponse(NamedList res) { super(res); - + // Parse indexinfo - indexInfo = (NamedList)res.get( "index" ); - - NamedList flds = (NamedList)res.get( "fields" ); - if (flds==null) { - flds = (NamedList) ((NamedList)res.get( "schema" )).get("fields"); + indexInfo = (NamedList) res.get("index"); + + NamedList flds = (NamedList) res.get("fields"); + if (flds == null) { + flds = (NamedList) ((NamedList) res.get("schema")).get("fields"); } - if( flds != null ) { - fieldInfo = new HashMap( ); - for( Map.Entry field : flds ) { - FieldInfo f = new FieldInfo( field.getKey() ); - f.read( (NamedList)field.getValue() ); - fieldInfo.put( field.getKey(), f ); + if (flds != null) { + fieldInfo = new HashMap(); + for (Map.Entry field : flds) { + FieldInfo f = new FieldInfo(field.getKey()); + f.read((NamedList) field.getValue()); + fieldInfo.put(field.getKey(), f); } } + + NamedList fldTypes = (NamedList) ((NamedList) res.get("schema")).get("types"); + if (fldTypes != null) { + fieldTypeInfo = new HashMap(); + for (Map.Entry fieldType : fldTypes) { + FieldTypeInfo ft = new FieldTypeInfo(fieldType.getKey()); + ft.read((NamedList) fieldType.getValue()); + fieldTypeInfo.put(fieldType.getKey(), ft); + } + } + } //---------------------------------------------------------------- //---------------------------------------------------------------- - - public String getIndexDirectory() - { - if( indexInfo == null ) return null; - return (String)indexInfo.get( "directory" ); + + public String getIndexDirectory() { + if (indexInfo == null) return null; + return (String) indexInfo.get("directory"); } - public Integer getNumDocs() - { - if( indexInfo == null ) return null; - return (Integer)indexInfo.get( "numDocs" ); + public Integer getNumDocs() { + if (indexInfo == null) return null; + return (Integer) indexInfo.get("numDocs"); } - public Integer getMaxDoc() - { - if( indexInfo == null ) return null; - return (Integer)indexInfo.get( "maxDoc" ); + public Integer getMaxDoc() { + if (indexInfo == null) return null; + return (Integer) indexInfo.get("maxDoc"); } - public Integer getNumTerms() - { - if( indexInfo == null ) return null; - return (Integer)indexInfo.get( "numTerms" ); + public Integer getNumTerms() { + if (indexInfo == null) return null; + return (Integer) indexInfo.get("numTerms"); } - public Map getFieldInfo() { + public Map getFieldTypeInfo() { + return fieldTypeInfo; + } + + public FieldTypeInfo getFieldTypeInfo(String name) { + return fieldTypeInfo.get(name); + } + + public NamedList getIndexInfo() { + return indexInfo; + } + + public Map getFieldInfo() { return fieldInfo; } - public FieldInfo getFieldInfo( String f ) { - return fieldInfo.get( f ); + public FieldInfo getFieldInfo(String f) { + return fieldInfo.get(f); } //---------------------------------------------------------------- - //---------------------------------------------------------------- } diff --git a/src/java/org/apache/solr/common/luke/FieldFlag.java b/src/java/org/apache/solr/common/luke/FieldFlag.java new file mode 100644 index 00000000000..a5e37e6140e --- /dev/null +++ b/src/java/org/apache/solr/common/luke/FieldFlag.java @@ -0,0 +1,43 @@ +package org.apache.solr.common.luke; + +/** + * The FieldFlag class is used to store + * + **/ +public enum FieldFlag { + INDEXED('I', "Indexed"), TOKENIZED('T', "Tokenized"), STORED('S', "Stored"), MULTI_VALUED('M', "Multivalued"), + TERM_VECTOR_STORED('V', "TermVector Stored"), TERM_VECTOR_OFFSET('o', "Store Offset With TermVector"), + TERM_VECTOR_POSITION('p', "Store Position With TermVector"), + OMIT_NORMS('O', "Omit Norms"), LAZY('L', "Lazy"), BINARY('B', "Binary"), COMPRESSED('C', "Compressed"), + SORT_MISSING_FIRST('f', "Sort Missing First"), SORT_MISSING_LAST('l', "Sort Missing Last"); + + private char abbreviation; + private String display; + + + FieldFlag(char abbreviation, String display) { + this.abbreviation = abbreviation; + this.display = display; + this.display.intern();//QUESTION: Need we bother here? + } + + public static FieldFlag getFlag(char abbrev){ + FieldFlag result = null; + FieldFlag [] vals = FieldFlag.values(); + for (int i = 0; i < vals.length; i++) { + if (vals[i].getAbbreviation() == abbrev){ + result = vals[i]; + break; + } + } + return result; + } + + public char getAbbreviation() { + return abbreviation; + } + + public String getDisplay() { + return display; + } + } diff --git a/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java b/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java index fb381366447..117905f6b9c 100644 --- a/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java +++ b/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java @@ -17,21 +17,6 @@ package org.apache.solr.handler.admin; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - import org.apache.lucene.document.Document; import org.apache.lucene.document.Fieldable; import org.apache.lucene.index.IndexReader; @@ -44,6 +29,7 @@ import org.apache.lucene.search.Sort; import org.apache.lucene.store.Directory; import org.apache.lucene.util.PriorityQueue; import org.apache.solr.common.SolrException; +import org.apache.solr.common.luke.FieldFlag; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; @@ -59,6 +45,13 @@ import org.apache.solr.search.DocList; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.search.SolrQueryParser; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + /** * This handler exposes the internal lucene index. It is inspired by and * modeled on Luke, the Lucene Index Browser by Andrzej Bialecki. @@ -150,26 +143,28 @@ public class LukeRequestHandler extends RequestHandlerBase info.add( "NOTE", "Document Frequency (df) is not updated when a document is marked for deletion. df values include deleted documents." ); rsp.add( "info", info ); } + + /** * @return a string representing a Fieldable's flags. */ private static String getFieldFlags( Fieldable f ) { StringBuilder flags = new StringBuilder(); - flags.append( (f != null && f.isIndexed()) ? 'I' : '-' ); - flags.append( (f != null && f.isTokenized()) ? 'T' : '-' ); - flags.append( (f != null && f.isStored()) ? 'S' : '-' ); - flags.append( (false) ? 'M' : '-' ); // SchemaField Specific - flags.append( (f != null && f.isTermVectorStored()) ? 'V' : '-' ); - flags.append( (f != null && f.isStoreOffsetWithTermVector()) ? 'o' : '-' ); - flags.append( (f != null && f.isStorePositionWithTermVector()) ? 'p' : '-' ); - flags.append( (f != null && f.getOmitNorms()) ? 'O' : '-' ); - flags.append( (f != null && f.isLazy()) ? 'L' : '-' ); - flags.append( (f != null && f.isBinary()) ? 'B' : '-' ); - flags.append( (f != null && f.isCompressed()) ? 'C' : '-' ); - flags.append( (false) ? 'f' : '-' ); // SchemaField Specific - flags.append( (false) ? 'l' : '-' ); // SchemaField Specific + flags.append( (f != null && f.isIndexed()) ? FieldFlag.INDEXED.getAbbreviation() : '-' ); + flags.append( (f != null && f.isTokenized()) ? FieldFlag.TOKENIZED.getAbbreviation() : '-' ); + flags.append( (f != null && f.isStored()) ? FieldFlag.STORED.getAbbreviation() : '-' ); + flags.append( (false) ? FieldFlag.MULTI_VALUED.getAbbreviation() : '-' ); // SchemaField Specific + flags.append( (f != null && f.isTermVectorStored()) ? FieldFlag.TERM_VECTOR_STORED.getAbbreviation() : '-' ); + flags.append( (f != null && f.isStoreOffsetWithTermVector()) ? FieldFlag.TERM_VECTOR_OFFSET.getAbbreviation() : '-' ); + flags.append( (f != null && f.isStorePositionWithTermVector()) ? FieldFlag.TERM_VECTOR_POSITION.getAbbreviation() : '-' ); + flags.append( (f != null && f.getOmitNorms()) ? FieldFlag.OMIT_NORMS.getAbbreviation() : '-' ); + flags.append( (f != null && f.isLazy()) ? FieldFlag.LAZY.getAbbreviation() : '-' ); + flags.append( (f != null && f.isBinary()) ? FieldFlag.BINARY.getAbbreviation() : '-' ); + flags.append( (f != null && f.isCompressed()) ? FieldFlag.COMPRESSED.getAbbreviation() : '-' ); + flags.append( (false) ? FieldFlag.SORT_MISSING_FIRST.getAbbreviation() : '-' ); // SchemaField Specific + flags.append( (false) ? FieldFlag.SORT_MISSING_LAST.getAbbreviation() : '-' ); // SchemaField Specific return flags.toString(); } @@ -185,41 +180,41 @@ public class LukeRequestHandler extends RequestHandlerBase boolean binary = false; // Currently not possible StringBuilder flags = new StringBuilder(); - flags.append( (f != null && f.indexed()) ? 'I' : '-' ); - flags.append( (t != null && t.isTokenized()) ? 'T' : '-' ); - flags.append( (f != null && f.stored()) ? 'S' : '-' ); - flags.append( (f != null && f.multiValued()) ? 'M' : '-' ); - flags.append( (f != null && f.storeTermVector() ) ? 'V' : '-' ); - flags.append( (f != null && f.storeTermOffsets() ) ? 'o' : '-' ); - flags.append( (f != null && f.storeTermPositions() ) ? 'p' : '-' ); - flags.append( (f != null && f.omitNorms()) ? 'O' : '-' ); - flags.append( (lazy) ? 'L' : '-' ); - flags.append( (binary) ? 'B' : '-' ); - flags.append( (f != null && f.isCompressed()) ? 'C' : '-' ); - flags.append( (f != null && f.sortMissingFirst() ) ? 'f' : '-' ); - flags.append( (f != null && f.sortMissingLast() ) ? 'l' : '-' ); + flags.append( (f != null && f.indexed()) ? FieldFlag.INDEXED.getAbbreviation() : '-' ); + flags.append( (t != null && t.isTokenized()) ? FieldFlag.TOKENIZED.getAbbreviation() : '-' ); + flags.append( (f != null && f.stored()) ? FieldFlag.STORED.getAbbreviation() : '-' ); + flags.append( (f != null && f.multiValued()) ? FieldFlag.MULTI_VALUED.getAbbreviation() : '-' ); + flags.append( (f != null && f.storeTermVector() ) ? FieldFlag.TERM_VECTOR_STORED.getAbbreviation() : '-' ); + flags.append( (f != null && f.storeTermOffsets() ) ? FieldFlag.TERM_VECTOR_OFFSET.getAbbreviation() : '-' ); + flags.append( (f != null && f.storeTermPositions() ) ? FieldFlag.TERM_VECTOR_POSITION.getAbbreviation() : '-' ); + flags.append( (f != null && f.omitNorms()) ? FieldFlag.OMIT_NORMS.getAbbreviation() : '-' ); + flags.append( (lazy) ? FieldFlag.LAZY.getAbbreviation() : '-' ); + flags.append( (binary) ? FieldFlag.BINARY.getAbbreviation() : '-' ); + flags.append( (f != null && f.isCompressed()) ? FieldFlag.COMPRESSED.getAbbreviation() : '-' ); + flags.append( (f != null && f.sortMissingFirst() ) ? FieldFlag.SORT_MISSING_FIRST.getAbbreviation() : '-' ); + flags.append( (f != null && f.sortMissingLast() ) ? FieldFlag.SORT_MISSING_LAST.getAbbreviation() : '-' ); return flags.toString(); } /** * @return a key to what each character means */ - private static SimpleOrderedMap getFieldFlagsKey() + public static SimpleOrderedMap getFieldFlagsKey() { SimpleOrderedMap key = new SimpleOrderedMap(); - key.add( "I", "Indexed" ); - key.add( "T", "Tokenized" ); - key.add( "S", "Stored" ); - key.add( "M", "Multivalued" ); - key.add( "V", "TermVector Stored" ); - key.add( "o", "Store Offset With TermVector" ); - key.add( "p", "Store Position With TermVector" ); - key.add( "O", "Omit Norms" ); - key.add( "L", "Lazy" ); - key.add( "B", "Binary" ); - key.add( "C", "Compressed" ); - key.add( "f", "Sort Missing First" ); - key.add( "l", "Sort Missing Last" ); + key.add(String.valueOf(FieldFlag.INDEXED.getAbbreviation()), FieldFlag.INDEXED.getDisplay() ); + key.add(String.valueOf(FieldFlag.TOKENIZED.getAbbreviation()), FieldFlag.TOKENIZED.getDisplay() ); + key.add( String.valueOf(FieldFlag.STORED.getAbbreviation()), FieldFlag.STORED.getDisplay() ); + key.add( String.valueOf(FieldFlag.MULTI_VALUED.getAbbreviation()), FieldFlag.MULTI_VALUED.getDisplay() ); + key.add( String.valueOf(FieldFlag.TERM_VECTOR_STORED.getAbbreviation()), FieldFlag.TERM_VECTOR_STORED.getDisplay() ); + key.add( String.valueOf(FieldFlag.TERM_VECTOR_OFFSET.getAbbreviation()), FieldFlag.TERM_VECTOR_OFFSET.getDisplay() ); + key.add( String.valueOf(FieldFlag.TERM_VECTOR_POSITION.getAbbreviation()), FieldFlag.TERM_VECTOR_POSITION.getDisplay() ); + key.add( String.valueOf(FieldFlag.OMIT_NORMS.getAbbreviation()), FieldFlag.OMIT_NORMS.getDisplay() ); + key.add( String.valueOf(FieldFlag.LAZY.getAbbreviation()), FieldFlag.LAZY.getDisplay() ); + key.add( String.valueOf(FieldFlag.BINARY.getAbbreviation()), FieldFlag.BINARY.getDisplay() ); + key.add( String.valueOf(FieldFlag.COMPRESSED.getAbbreviation()), FieldFlag.COMPRESSED.getDisplay() ); + key.add( String.valueOf(FieldFlag.SORT_MISSING_FIRST.getAbbreviation()), FieldFlag.SORT_MISSING_FIRST.getDisplay() ); + key.add( String.valueOf(FieldFlag.SORT_MISSING_LAST.getAbbreviation()), FieldFlag.SORT_MISSING_LAST.getDisplay() ); return key; } @@ -372,7 +367,8 @@ public class LukeRequestHandler extends RequestHandlerBase SimpleOrderedMap field = new SimpleOrderedMap(); field.add( "fields", typeusemap.get( ft.getTypeName() ) ); field.add( "tokenized", ft.isTokenized() ); - field.add( "analyzer", ft.getAnalyzer()+"" ); + field.add("className", ft.getClass().getName()); + field.add( "analyzer", ft.getAnalyzer().getClass().getName()); types.add( ft.getTypeName(), field ); }