lucene-solr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From yo...@apache.org
Subject svn commit: r372455 [5/11] - in /incubator/solr/trunk: ./ src/ src/apps/ src/apps/SolarTest/ src/apps/SolarTest/src/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/solr/ src/java/org/apache/solr/analysis/ src/java/org/apache/solr/core...
Date Thu, 26 Jan 2006 05:40:05 GMT
Added: incubator/solr/trunk/src/java/org/apache/solr/request/XMLWriter.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/request/XMLWriter.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/request/XMLWriter.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/request/XMLWriter.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,620 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.request;
+
+import org.apache.solr.util.NamedList;
+import org.apache.solr.util.XML;
+import org.apache.solr.search.SolrIndexSearcher;
+import org.apache.solr.search.DocList;
+import org.apache.solr.search.DocIterator;
+import org.apache.solr.search.DocSet;
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.schema.SchemaField;
+
+import java.io.Writer;
+import java.io.IOException;
+import java.util.*;
+
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.Document;
+/**
+ * @author yonik
+ * @version $Id: XMLWriter.java,v 1.16 2005/12/02 04:31:06 yonik Exp $
+ */
+final public class XMLWriter {
+  //
+  // static thread safe part
+  //
+  private static final char[] XML_START1="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".toCharArray();
+
+  private static final char[] XML_STYLESHEET="<?xml-stylesheet type=\"text/xsl\" href=\"/admin/".toCharArray();
+  private static final char[] XML_STYLESHEET_END=".xsl\"?>\n".toCharArray();
+
+  private static final char[] XML_START2_SCHEMA=(
+  "<response xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+  +" xsi:noNamespaceSchemaLocation=\"http://pi.cnet.com/cnet-search/response.xsd\">\n"
+          ).toCharArray();
+  private static final char[] XML_START2_NOSCHEMA=(
+  "<response>\n"
+          ).toCharArray();
+
+
+  public static void writeResponse(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) throws IOException {
+
+    // get total time up until now
+    int qtime=(int)(rsp.getEndTime() - req.getStartTime());
+
+    String ver = req.getParam("version");
+
+    writer.write(XML_START1);
+
+    String stylesheet = req.getParam("stylesheet");
+    if (stylesheet != null && stylesheet.length() > 0) {
+      writer.write(XML_STYLESHEET);
+      writer.write(stylesheet);
+      writer.write(XML_STYLESHEET_END);
+    }
+
+    String noSchema = req.getParam("noSchema");
+    // todo - change when schema becomes available?
+    if (false && noSchema == null)
+      writer.write(XML_START2_SCHEMA);
+    else
+      writer.write(XML_START2_NOSCHEMA);
+
+    writer.write("<responseHeader><status>");
+    writer.write('0');  // it's 0 (success) if we got this far...
+    writer.write("</status><QTime>");
+    writer.write(Integer.toString((int)qtime));
+    writer.write("</QTime></responseHeader>\n");
+
+    //
+    // create an instance for each request to handle
+    // non-thread safe stuff (indentation levels, etc)
+    // and to encapsulate writer, schema, and searcher so
+    // they don't have to be passed around in every function.
+    //
+    XMLWriter xw = new XMLWriter(writer, req.getSchema(), req.getSearcher(), ver);
+    xw.defaultFieldList = rsp.getReturnFields();
+
+    String indent = req.getParam("indent");
+    if (indent != null) {
+      if ("".equals(indent) || "off".equals(indent)) {
+        xw.setIndent(false);
+      } else {
+        xw.setIndent(true);
+      }
+    }
+
+    NamedList lst = rsp.getValues();
+    int sz = lst.size();
+    for (int i=0; i<sz; i++) {
+      xw.writeVal(lst.getName(i),lst.getVal(i));
+    }
+
+    writer.write("\n</response>\n");
+  }
+
+
+  ////////////////////////////////////////////////////////////
+  // request instance specific (non-static, not shared between threads)
+  ////////////////////////////////////////////////////////////
+
+  private final Writer writer;
+  private final IndexSchema schema; // needed to write fields of docs
+  private final SolrIndexSearcher searcher;  // needed to retrieve docs
+
+  private int level;
+  private boolean defaultIndent=false;
+  private boolean doIndent=false;
+
+  // fieldList... the set of fields to return for each document
+  private Set<String> defaultFieldList;
+
+
+  // if a list smaller than this threshold is encountered, elements
+  // will be written on the same line.
+  // maybe constructed types should always indent first?
+  private final int indentThreshold=0;
+
+  private final int version;
+
+
+  // temporary working objects...
+  // be careful not to use these recursively...
+  private final ArrayList tlst = new ArrayList();
+  private final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+  private final StringBuilder sb = new StringBuilder();
+
+  XMLWriter(Writer writer, IndexSchema schema, SolrIndexSearcher searcher, String version) {
+    this.writer = writer;
+    this.schema = schema;
+    this.searcher = searcher;
+    float ver = version==null? 2.1f : Float.parseFloat(version);
+    this.version = (int)(ver*1000);
+  }
+
+  //
+  // Functions to manipulate the current logical nesting level.
+  // Any indentation will be partially based on level.
+  //
+  public void setLevel(int level) { this.level = level; }
+  public int level() { return level; }
+  public int incLevel() { return ++level; }
+  public int decLevel() { return --level; }
+  public void setIndent(boolean doIndent) {
+    this.doIndent = doIndent;
+    defaultIndent = doIndent;
+  }
+
+  public void writeAttr(String name, String val) throws IOException {
+    if (val != null) {
+      writer.write(' ');
+      writer.write(name);
+      writer.write("=\"");
+      writer.write(val);
+      writer.write('"');
+    }
+  }
+
+  public void startTag(String tag, String name, boolean closeTag) throws IOException {
+    if (doIndent) indent();
+
+    writer.write('<');
+    writer.write(tag);
+    if (name!=null) {
+      writer.write(" name=\"");
+      writer.write(name);
+      if (closeTag) {
+        writer.write("\"/>");
+      } else {
+        writer.write("\">");
+      }
+    } else {
+      if (closeTag) {
+        writer.write("/>");
+      } else {
+        writer.write('>');
+      }
+    }
+  }
+
+  private static final String[] indentArr = new String[] {
+    "\n",
+    "\n ",
+    "\n  ",
+    "\n\t",
+    "\n\t ",
+    "\n\t  ",  // could skip this one (the only 3 char seq)
+    "\n\t\t" };
+
+  public void indent() throws IOException {
+     indent(level);
+  }
+
+  public void indent(int lev) throws IOException {
+    int arrsz = indentArr.length-1;
+    // another option would be lev % arrsz (wrap around)
+    String istr = indentArr[ lev > arrsz ? arrsz : lev ];
+    writer.write(istr);
+  }
+
+  private static final Comparator fieldnameComparator = new Comparator() {
+    public int compare(Object o, Object o1) {
+      Field f1 = (Field)o; Field f2 = (Field)o1;
+      int cmp = f1.name().compareTo(f2.name());
+      return cmp;
+      // note - the sort is stable, so this should not have affected the ordering
+      // of fields with the same name w.r.t eachother.
+    }
+  };
+
+  public final void writeDoc(String name, Document doc, Set<String> returnFields, float score, boolean includeScore) throws IOException {
+    startTag("doc", name, false);
+    incLevel();
+
+    if (includeScore) {
+      writeFloat("score", score);
+    }
+
+
+    // Lucene Documents have multivalued types as multiple fields
+    // with the same name.
+    // The XML needs to represent these as
+    // an array.  The fastest way to detect multiple fields
+    // with the same name is to sort them first.
+
+    Enumeration ee = doc.fields();
+
+    // using global tlst here, so we shouldn't call any other
+    // function that uses it until we are done.
+    tlst.clear();
+    while (ee.hasMoreElements()) {
+      Field ff = (Field) ee.nextElement();
+      // skip this field if it is not a field to be returned.
+      if (returnFields!=null && !returnFields.contains(ff.name())) {
+        continue;
+      }
+      tlst.add(ff);
+    }
+    Collections.sort(tlst, fieldnameComparator);
+
+    int sz = tlst.size();
+    int fidx1 = 0, fidx2 = 0;
+    while (fidx1 < sz) {
+      Field f1 = (Field)tlst.get(fidx1);
+      String fname = f1.name();
+
+      // find the end of fields with this name
+      fidx2 = fidx1+1;
+      while (fidx2 < sz && fname.equals(((Field)tlst.get(fidx2)).name()) ) {
+        fidx2++;
+      }
+
+      /***
+      // more efficient to use getFieldType instead of
+      // getField since that way dynamic fields won't have
+      // to create a SchemaField on the fly.
+      FieldType ft = schema.getFieldType(fname);
+      ***/
+
+      SchemaField sf = schema.getField(fname);
+
+      if (fidx1+1 == fidx2) {
+        // single field value
+        if (version>=2100 && sf.multiValued()) {
+          startTag("arr",fname,false);
+          doIndent=false;
+          sf.write(this, null, f1);
+          writer.write("</arr>");
+          doIndent=defaultIndent;
+        } else {
+          sf.write(this, f1.name(), f1);
+        }
+      } else {
+        // multiple fields with same name detected
+
+        startTag("arr",fname,false);
+        incLevel();
+        doIndent=false;
+        int cnt=0;
+        for (int i=fidx1; i<fidx2; i++) {
+          if (defaultIndent && ++cnt==4) { // only indent every 4th item
+            indent();
+            cnt=0;
+          }
+          sf.write(this, null, (Field)tlst.get(i));
+        }
+        decLevel();
+        // if (doIndent) indent();
+        writer.write("</arr>");
+        // doIndent=true;
+        doIndent=defaultIndent;
+      }
+      fidx1 = fidx2;
+    }
+
+    decLevel();
+    if (doIndent) indent();
+    writer.write("</doc>");
+  }
+
+  public final void writeDocList(String name, DocList ids, Set<String> fields) throws IOException {
+    boolean includeScore=false;
+    if (fields!=null) {
+      includeScore = fields.contains("score");
+      if (fields.size()==0 || (fields.size()==1 && includeScore) || fields.contains("*")) {
+        fields=null;  // null means return all stored fields
+      }
+    }
+
+    int sz=ids.size();
+
+    if (doIndent) indent();
+    writer.write("<result");
+    writeAttr("name",name);
+    writeAttr("numFound",Integer.toString(ids.matches()));
+    writeAttr("start",Integer.toString(ids.offset()));
+    if (includeScore) {
+      writeAttr("maxScore",Float.toString(ids.maxScore()));
+    }
+    if (sz==0) {
+      writer.write("/>");
+      return;
+    } else {
+      writer.write('>');
+    }
+
+    incLevel();
+    DocIterator iterator = ids.iterator();
+    for (int i=0; i<sz; i++) {
+      int id = iterator.nextDoc();
+      Document doc = searcher.doc(id);
+      writeDoc(null, doc, fields, (includeScore ? iterator.score() : 0.0f), includeScore);
+    }
+    decLevel();
+
+    if (doIndent) indent();
+    writer.write("</result>");
+  }
+
+
+  public void writeVal(String name, Object val) throws IOException {
+
+    // if there get to be enough types, perhaps hashing on the type
+    // to get a handler might be faster (but types must be exact to do that...)
+
+    // go in order of most common to least common
+    if (val==null) {
+      writeNull(name);
+    } else if (val instanceof String) {
+      writeStr(name, (String)val);
+    } else if (val instanceof Integer) {
+      // it would be slower to pass the int ((Integer)val).intValue()
+      writeInt(name, val.toString());
+    } else if (val instanceof Boolean) {
+      // could be optimized... only two vals
+      writeBool(name, val.toString());
+    } else if (val instanceof Long) {
+      writeLong(name, val.toString());
+    } else if (val instanceof Date) {
+      writeDate(name,(Date)val);
+    } else if (val instanceof Float) {
+      // we pass the float instead of using toString() because
+      // it may need special formatting. same for double.
+      writeFloat(name, ((Float)val).floatValue());
+    } else if (val instanceof Double) {
+      writeDouble(name, ((Double)val).doubleValue());
+    } else if (val instanceof Document) {
+      writeDoc(name, (Document)val, null, 0.0f, false);
+    } else if (val instanceof DocList) {
+      // requires access to IndexReader
+      writeDocList(name, (DocList)val, defaultFieldList);
+    } else if (val instanceof DocSet) {
+      // how do we know what fields to read?
+      // todo: have a DocList/DocSet wrapper that
+      // restricts the fields to write...?
+    } else if (val instanceof Map) {
+      writeMap(name, (Map)val);
+    } else if (val instanceof NamedList) {
+      writeNamedList(name, (NamedList)val);
+    } else if (val instanceof Collection) {
+      writeArray(name,(Collection)val);
+    } else if (val instanceof Object[]) {
+      writeArray(name,(Object[])val);
+    } else {
+      // default...
+      writeStr(name, val.getClass().getName() + ':' + val.toString());
+    }
+  }
+
+  //
+  // Generic compound types
+  //
+
+  public void writeNamedList(String name, NamedList val) throws IOException {
+    int sz = val.size();
+    startTag("lst", name, sz<=0);
+
+    if (sz<indentThreshold) {
+      doIndent=false;
+    }
+
+    incLevel();
+    for (int i=0; i<sz; i++) {
+      writeVal(val.getName(i),val.getVal(i));
+    }
+    decLevel();
+
+    if (sz > 0) {
+      if (doIndent) indent();
+      writer.write("</lst>");
+    }
+  }
+
+
+
+  //A map is currently represented as a named list
+  public void writeMap(String name, Map val) throws IOException {
+    Map map = val;
+    int sz = map.size();
+    startTag("lst", name, sz<=0);
+    incLevel();
+    for (Map.Entry entry : (Set<Map.Entry>)map.entrySet()) {
+      // possible class-cast exception here...
+      String k = (String)entry.getKey();
+      Object v = entry.getValue();
+      // if (sz<indentThreshold) indent();
+      writeVal(k,v);
+    }
+    decLevel();
+    if (sz > 0) {
+      if (doIndent) indent();
+      writer.write("</lst>");
+    }
+  }
+
+  public void writeArray(String name, Object[] val) throws IOException {
+    writeArray(name, Arrays.asList(val));
+  }
+
+  public void writeArray(String name, Collection val) throws IOException {
+    int sz = val.size();
+    startTag("arr", name, sz<=0);
+    incLevel();
+    for (Object o : val) {
+      // if (sz<indentThreshold) indent();
+      writeVal(null, o);
+    }
+    decLevel();
+    if (sz > 0) {
+      if (doIndent) indent();
+      writer.write("</arr>");
+    }
+  }
+
+  //
+  // Primitive types
+  //
+
+  public void writeNull(String name) throws IOException {
+    writePrim("null",name,"",false);
+  }
+
+  public void writeStr(String name, String val) throws IOException {
+    writePrim("str",name,val,true);
+  }
+
+  public void writeInt(String name, String val) throws IOException {
+    writePrim("int",name,val,false);
+  }
+
+  public void writeInt(String name, int val) throws IOException {
+    writeInt(name,Integer.toString(val));
+  }
+
+  public void writeLong(String name, String val) throws IOException {
+    writePrim("long",name,val,false);
+  }
+
+  public void writeLong(String name, long val) throws IOException {
+    writeLong(name,Long.toString(val));
+  }
+
+  public void writeBool(String name, String val) throws IOException {
+    writePrim("bool",name,val,false);
+  }
+
+  public void writeBool(String name, boolean val) throws IOException {
+    writeBool(name,Boolean.toString(val));
+  }
+
+  public void writeFloat(String name, String val) throws IOException {
+    writePrim("float",name,val,false);
+  }
+
+  public void writeFloat(String name, float val) throws IOException {
+    writeFloat(name,Float.toString(val));
+  }
+
+  public void writeDouble(String name, String val) throws IOException {
+    writePrim("double",name,val,false);
+  }
+
+  public void writeDouble(String name, double val) throws IOException {
+    writeDouble(name,Double.toString(val));
+  }
+
+  public void writeDate(String name, Date val) throws IOException {
+    // using a stringBuilder for numbers can be nice since
+    // a temporary string isn't used (it's added directly to the
+    // builder's buffer.
+
+    cal.setTime(val);
+
+    sb.setLength(0);
+    int i = cal.get(Calendar.YEAR);
+    sb.append(i);
+    sb.append('-');
+    i = cal.get(Calendar.MONTH) + 1;  // 0 based, so add 1
+    if (i<10) sb.append('0');
+    sb.append(i);
+    sb.append('-');
+    i=cal.get(Calendar.DAY_OF_MONTH);
+    if (i<10) sb.append('0');
+    sb.append(i);
+    sb.append('T');
+    i=cal.get(Calendar.HOUR_OF_DAY); // 24 hour time format
+    if (i<10) sb.append('0');
+    sb.append(i);
+    sb.append(':');
+    i=cal.get(Calendar.MINUTE);
+    if (i<10) sb.append('0');
+    sb.append(i);
+    sb.append(':');
+    i=cal.get(Calendar.SECOND);
+    if (i<10) sb.append('0');
+    sb.append(i);
+    i=cal.get(Calendar.MILLISECOND);
+    if (i != 0) {
+      sb.append('.');
+      if (i<100) sb.append('0');
+      if (i<10) sb.append('0');
+      sb.append(i);
+
+      // handle canonical format specifying fractional
+      // seconds shall not end in '0'.  Given the slowness of
+      // integer div/mod, simply checking the last character
+      // is probably the fastest way to check.
+      int lastIdx = sb.length()-1;
+      if (sb.charAt(lastIdx)=='0') {
+        lastIdx--;
+        if (sb.charAt(lastIdx)=='0') {
+          lastIdx--;
+        }
+        sb.setLength(lastIdx+1);
+      }
+
+    }
+    sb.append('Z');
+    writeDate(name, sb.toString());
+  }
+
+  public void writeDate(String name, String val) throws IOException {
+    writePrim("date",name,val,false);
+  }
+
+
+  //
+  // OPT - specific writeInt, writeFloat, methods might be faster since
+  // there would be less write calls (write("<int name=\"" + name + ... + </int>)
+  //
+  public void writePrim(String tag, String name, String val, boolean escape) throws IOException {
+    // OPT - we could use a temp char[] (or a StringBuilder) and if the
+    // size was small enough to fit (if escape==false we can calc exact size)
+    // then we could put things directly in the temp buf.
+    // need to see what percent of CPU this takes up first though...
+    // Could test a reusable StringBuilder...
+
+    // is this needed here???
+    // Only if a fieldtype calls writeStr or something
+    // with a null val instead of calling writeNull
+    /***
+    if (val==null) {
+      if (name==null) writer.write("<null/>");
+      else writer.write("<null name=\"" + name + "/>");
+    }
+    ***/
+
+    int contentLen=val.length();
+
+    startTag(tag, name, contentLen==0);
+    if (contentLen==0) return;
+
+    if (escape) {
+      XML.escapeCharData(val,writer);
+    } else {
+      writer.write(val,0,contentLen);
+    }
+
+    writer.write("</");
+    writer.write(tag);
+    writer.write('>');
+  }
+
+
+}

Propchange: incubator/solr/trunk/src/java/org/apache/solr/request/XMLWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/BCDIntField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/BCDIntField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/BCDIntField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/BCDIntField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,60 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.function.ValueSource;
+import org.apache.lucene.document.Field;
+import org.apache.solr.util.BCDUtils;
+import org.apache.solr.request.XMLWriter;
+
+import java.util.Map;
+import java.io.IOException;
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public class BCDIntField extends FieldType {
+  protected void init(IndexSchema schema, Map<String,String> args) {
+  }
+
+  public SortField getSortField(SchemaField field,boolean reverse) {
+    return getStringSort(field,reverse);
+  }
+
+  public ValueSource getValueSource(SchemaField field) {
+    throw new UnsupportedOperationException("ValueSource not implemented");
+  }
+
+  public String toInternal(String val) {
+    return BCDUtils.base10toBase10kSortableInt(val);
+  }
+
+  public String toExternal(Field f) {
+    return indexedToReadable(f.stringValue());
+  }
+
+  public String indexedToReadable(String indexedForm) {
+    return BCDUtils.base10kSortableIntToBase10(indexedForm);
+  }
+
+  public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+    xmlWriter.writeInt(name,toExternal(f));
+  }
+}
+
+

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/BCDIntField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/BCDLongField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/BCDLongField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/BCDLongField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/BCDLongField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.solr.request.XMLWriter;
+import org.apache.lucene.document.Field;
+
+import java.io.IOException;
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public class BCDLongField extends BCDIntField {
+  public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+    xmlWriter.writeLong(name,toExternal(f));
+  }
+}

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/BCDLongField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/BCDStrField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/BCDStrField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/BCDStrField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/BCDStrField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.solr.request.XMLWriter;
+import org.apache.lucene.document.Field;
+
+import java.io.IOException;
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public class BCDStrField extends BCDIntField {
+  public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+    xmlWriter.writeStr(name,toExternal(f));
+  }
+}

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/BCDStrField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/BoolField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/BoolField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/BoolField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/BoolField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,97 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.function.ValueSource;
+import org.apache.lucene.search.function.OrdFieldSource;
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.Tokenizer;
+import org.apache.lucene.document.Field;
+import org.apache.solr.request.XMLWriter;
+
+import java.util.Map;
+import java.io.Reader;
+import java.io.IOException;
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public class BoolField extends FieldType {
+  protected void init(IndexSchema schema, Map<String,String> args) {
+  }
+
+  public SortField getSortField(SchemaField field,boolean reverse) {
+    return getStringSort(field,reverse);
+  }
+
+  public ValueSource getValueSource(SchemaField field) {
+    return new OrdFieldSource(field.name);
+  }
+
+  // avoid instantiating every time...
+  protected final static Token TRUE_TOKEN = new Token("T",0,1);
+  protected final static Token FALSE_TOKEN = new Token("F",0,1);
+
+  ////////////////////////////////////////////////////////////////////////
+  // TODO: look into creating my own queryParser that can more efficiently
+  // handle single valued non-text fields (int,bool,etc) if needed.
+
+
+  protected final static Analyzer boolAnalyzer = new Analyzer() {
+      public TokenStream tokenStream(String fieldName, Reader reader) {
+        return new Tokenizer(reader) {
+          boolean done=false;
+          public Token next() throws IOException {
+            if (done) return null;
+            done=true;
+            int ch = input.read();
+            if (ch==-1) return null;
+            return (ch=='t' || ch=='T' || ch=='1') ? TRUE_TOKEN : FALSE_TOKEN;
+          }
+        };
+      }
+    };
+
+  public Analyzer getAnalyzer() {
+    return boolAnalyzer;
+  }
+
+  public Analyzer getQueryAnalyzer() {
+    return boolAnalyzer;
+  }
+
+  public String toInternal(String val) {
+    char ch = (val!=null && val.length()>0) ? val.charAt(0) : 0;
+    return (ch=='1' || ch=='t' || ch=='T') ? "T" : "F";
+  }
+
+  public String toExternal(Field f) {
+    return indexedToReadable(f.stringValue());
+  }
+
+  public String indexedToReadable(String indexedForm) {
+    char ch = indexedForm.charAt(0);
+    return ch=='T' ? "true" : "false";
+  }
+
+  public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+    xmlWriter.writeBool(name, f.stringValue().charAt(0) =='T');
+  }
+}

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/BoolField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/DateField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/DateField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/DateField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/DateField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,94 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.solr.core.SolrException;
+import org.apache.solr.request.XMLWriter;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.function.ValueSource;
+import org.apache.lucene.search.function.OrdFieldSource;
+
+import java.util.Map;
+import java.io.IOException;
+
+/***
+Date Format for the XML, incoming and outgoing:
+
+A date field shall be of the form 1995-12-31T23:59:59Z
+The trailing "Z" designates UTC time and is mandatory.
+Optional fractional seconds are allowed: 1995-12-31T23:59:59.999Z
+All other parts are mandatory.
+
+This format was derived to be standards compliant (ISO 8601) and is a more
+restricted form of the canonical representation of dateTime from XML schema part 2.
+http://www.w3.org/TR/xmlschema-2/#dateTime
+
+"In 1970 the Coordinated Universal Time system was devised by an international
+advisory group of technical experts within the International Telecommunication
+Union (ITU).  The ITU felt it was best to designate a single abbreviation for
+use in all languages in order to minimize confusion.  Since unanimous agreement
+could not be achieved on using either the English word order, CUT, or the
+French word order, TUC, the acronym UTC was chosen as a compromise."
+***/
+
+// The XML (external) date format will sort correctly, except if
+// fractions of seconds are present (because '.' is lower than 'Z').
+// The easiest fix is to simply remove the 'Z' for the internal
+// format.
+
+// TODO: make a FlexibleDateField that can accept dates in multiple
+// formats, better for human entered dates.
+
+// TODO: make a DayField that only stores the day?
+
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public class DateField extends FieldType {
+  protected void init(IndexSchema schema, Map<String,String> args) {
+  }
+
+  public String toInternal(String val) {
+    int len=val.length();
+    if (val.charAt(len-1)=='Z') {
+      return val.substring(0,len-1);
+    }
+    throw new SolrException(1,"Invalid Date String:'" +val+'\'');
+  }
+
+  public String indexedToReadable(String indexedForm) {
+    return indexedForm + 'Z';
+  }
+
+  public String toExternal(Field f) {
+    return indexedToReadable(f.stringValue());
+  }
+
+  public SortField getSortField(SchemaField field,boolean reverse) {
+    return getStringSort(field,reverse);
+  }
+
+  public ValueSource getValueSource(SchemaField field) {
+    return new OrdFieldSource(field.name);
+  }
+
+  public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+    xmlWriter.writeDate(name, toExternal(f));
+  }
+}

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/DateField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/DoubleField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/DoubleField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/DoubleField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/DoubleField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,50 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.function.ValueSource;
+import org.apache.lucene.search.function.FloatFieldSource;
+import org.apache.lucene.document.Field;
+import org.apache.solr.request.XMLWriter;
+
+import java.util.Map;
+import java.io.IOException;
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public class DoubleField extends FieldType {
+  protected void init(IndexSchema schema, Map<String,String> args) {
+    restrictProps(SORT_MISSING_FIRST | SORT_MISSING_LAST);
+  }
+
+  /////////////////////////////////////////////////////////////
+  // TODO: ACK.. there is currently no SortField.DOUBLE!
+  public SortField getSortField(SchemaField field,boolean reverse) {
+    return new SortField(field.name,SortField.FLOAT, reverse);
+  }
+
+  public ValueSource getValueSource(SchemaField field) {
+    // fieldCache doesn't support double
+    return new FloatFieldSource(field.name);
+  }
+
+  public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+    xmlWriter.writeDouble(name, f.stringValue());
+  }
+}

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/DoubleField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/FieldProperties.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/FieldProperties.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/FieldProperties.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/FieldProperties.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,144 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * @author yonik
+ * @version $Id$
+ */
+abstract class FieldProperties {
+
+  // use a bitfield instead of many different boolean variables since
+  // many of the variables are independent or semi-independent.
+
+  // bit values for boolean field properties.
+  final static int INDEXED             = 0x00000001;
+  final static int TOKENIZED           = 0x00000002;
+  final static int STORED              = 0x00000004;
+  final static int BINARY              = 0x00000008;
+  final static int COMPRESSED          = 0x00000010;
+  final static int OMIT_NORMS          = 0x00000020;
+  final static int STORE_TERMVECTORS   = 0x00000040;
+  final static int STORE_TERMPOSITIONS = 0x00000080;
+  final static int STORE_TERMOFFSETS   = 0x00000100;
+
+  final static int MULTIVALUED         = 0x00000200;
+  final static int SORT_MISSING_FIRST  = 0x00000400;
+  final static int SORT_MISSING_LAST   = 0x00000800;
+
+  static final String[] propertyNames = {
+          "indexed", "tokenized", "stored",
+          "binary", "compressed", "omitNorms",
+          "termVectors", "termPositions", "termOffsets",
+          "multiValued",
+          "sortMissingFirst","sortMissingLast"
+  };
+
+  static final Map<String,Integer> propertyMap = new HashMap<String,Integer>();
+  static {
+    for (String prop : propertyNames) {
+      propertyMap.put(prop, propertyNameToInt(prop));
+    }
+  }
+
+
+  /** Returns the symbolic name for the property. */
+  static String getPropertyName(int property) {
+    return propertyNames[ Integer.numberOfTrailingZeros(property) ];
+  }
+
+  static int propertyNameToInt(String name) {
+    for (int i=0; i<propertyNames.length; i++) {
+      if (propertyNames[i].equals(name)) {
+        return 1 << i;
+      }
+    }
+    return 0;
+  }
+
+
+  static String propertiesToString(int properties) {
+    StringBuilder sb = new StringBuilder();
+    boolean first=true;
+    while (properties != 0) {
+      if (!first) sb.append(',');
+      first=false;
+      int bitpos = Integer.numberOfTrailingZeros(properties);
+      sb.append(getPropertyName(1 << bitpos));
+      properties &= ~(1<<bitpos);  // clear that bit position
+    }
+    return sb.toString();
+  }
+
+  static boolean on(int bitfield, int props) {
+    return (bitfield & props) != 0;
+  }
+
+  static boolean off(int bitfield, int props) {
+    return (bitfield & props) == 0;
+  }
+
+  /***
+  static int normalize(int properties) {
+    int p = properties;
+    if (on(p,TOKENIZED) && off(p,INDEXED)) {
+      throw new RuntimeException("field must be indexed to be tokenized.");
+    }
+
+    if (on(p,STORE_TERMPOSITIONS)) p|=STORE_TERMVECTORS;
+    if (on(p,STORE_TERMOFFSETS)) p|=STORE_TERMVECTORS;
+    if (on(p,STORE_TERMOFFSETS) && off(p,INDEXED)) {
+      throw new RuntimeException("field must be indexed to store term vectors.");
+    }
+
+    if (on(p,OMIT_NORMS) && off(p,INDEXED)) {
+      throw new RuntimeException("field must be indexed for norms to be omitted.");
+    }
+
+    if (on(p,SORT_MISSING_FIRST) && on(p,SORT_MISSING_LAST)) {
+      throw new RuntimeException("conflicting options sortMissingFirst,sortMissingLast.");
+    }
+
+    if ((on(p,SORT_MISSING_FIRST) || on(p,SORT_MISSING_LAST)) && off(p,INDEXED)) {
+      throw new RuntimeException("field must be indexed to be sorted.");
+    }
+
+    if ((on(p,BINARY) || on(p,COMPRESSED)) && off(p,STORED)) {
+      throw new RuntimeException("field must be stored for compressed or binary options.");
+    }
+
+    return p;
+  }
+  ***/
+
+
+  static int parseProperties(Map<String,String> properties, boolean which) {
+    int props = 0;
+    for (String prop : properties.keySet()) {
+      if (propertyMap.get(prop)==null) continue;
+      String val = properties.get(prop);
+      if (Boolean.parseBoolean(val) == which) {
+        props |= propertyNameToInt(prop);
+      }
+    }
+    return props;
+  }
+
+}

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/FieldProperties.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/FieldType.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/FieldType.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/FieldType.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/FieldType.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,271 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.lucene.document.Field;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.Tokenizer;
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.function.ValueSource;
+import org.apache.lucene.search.function.OrdFieldSource;
+import org.apache.solr.search.Sorting;
+import org.apache.solr.request.XMLWriter;
+
+import java.util.logging.Logger;
+import java.util.Map;
+import java.util.HashMap;
+import java.io.Reader;
+import java.io.IOException;
+
+/**
+ * Base class for all field types used by an index schema.
+ *
+ * @author yonik
+ * @version $Id: FieldType.java,v 1.14 2006/01/06 04:23:15 yonik Exp $
+ */
+public abstract class FieldType extends FieldProperties {
+  public static final Logger log = Logger.getLogger(FieldType.class.getName());
+
+  protected String typeName;  // the name of the type, not the name of the field
+  protected Map<String,String> args;  // additional arguments
+  protected int trueProperties;   // properties explicitly set to true
+  protected int falseProperties;  // properties explicitly set to false
+  int properties;
+
+  // these are common enough, they were moved to the base class to handle.
+  // not all subclasses will be able to support these options.
+  protected int positionIncrementGap;
+
+  protected boolean isTokenized() {
+    return (properties & TOKENIZED) != 0;
+  }
+
+  /** subclasses should initialize themselves with the args provided
+   * and remove valid arguments.  leftover arguments will cause an exception.
+   * Common boolean properties have already been handled.
+   *
+   */
+  protected void init(IndexSchema schema, Map<String,String> args) {
+  }
+
+  // Handle additional arguments...
+  void setArgs(IndexSchema schema, Map<String,String> args) {
+    // default to STORED and INDEXED, and MULTIVALUED depending on schema version
+    properties = (STORED | INDEXED);
+    if (schema.getVersion()< 1.1f) properties |= MULTIVALUED;
+
+    this.args=args;
+    Map<String,String> initArgs = new HashMap<String,String>(args);
+
+    String str;
+
+    str = initArgs.get("positionIncrementGap");
+    if (str!=null) positionIncrementGap = Integer.parseInt(str);
+    initArgs.remove("positionIncrementGap");
+
+    trueProperties = FieldProperties.parseProperties(initArgs,true);
+    falseProperties = FieldProperties.parseProperties(initArgs,false);
+
+    properties &= ~falseProperties;
+    properties |= trueProperties;
+
+    for (String prop : FieldProperties.propertyNames) initArgs.remove(prop);
+
+    init(schema, initArgs);
+
+    if (initArgs.size() > 0) {
+      throw new RuntimeException("schema fieldtype " + typeName
+              + "("+ this.getClass().getName() + ")"
+              + " invalid arguments:" + initArgs);
+    }
+  }
+
+  protected void restrictProps(int props) {
+    if ((properties & props) != 0) {
+      throw new RuntimeException("schema fieldtype " + typeName
+              + "("+ this.getClass().getName() + ")"
+              + " invalid properties:" + propertiesToString(properties & props));
+    }
+  }
+
+
+  public String getTypeName() {
+    return typeName;
+  }
+
+  void setTypeName(String typeName) {
+    this.typeName = typeName;
+  }
+
+  public String toString() {
+    return typeName + "{class=" + this.getClass().getName()
+//            + propertiesToString(properties)
+            + (analyzer != null ? ",analyzer=" + analyzer.getClass().getName() : "")
+            + ",args=" + args
+            +"}";
+  }
+
+
+  // used for adding a document when a field needs to be created from a type and a string
+  // by default, the indexed value is the same as the stored value (taken from toInternal())
+  // Having a different representation for external, internal, and indexed would present quite
+  // a few problems given the current Lucene architecture.  An analyzer for adding docs would
+  // need to translate internal->indexed while an analyzer for querying would need to
+  // translate external->indexed.
+  //
+  // The only other alternative to having internal==indexed would be to have
+  // internal==external.
+  // In this case, toInternal should convert to the indexed representation,
+  // toExternal() should do nothing, and createField() should *not* call toInternal,
+  // but use the external value and set tokenized=true to get Lucene to convert
+  // to the internal(indexed) form.
+  public Field createField(SchemaField field, String externalVal, float boost) {
+    String val = toInternal(externalVal);
+    if (val==null) return null;
+    Field f =  new Field(field.getName(), val, field.stored(), field.indexed(), isTokenized());
+    f.setOmitNorms(field.omitNorms());
+    f.setBoost(boost);
+    return f;
+  }
+
+
+  // Convert an external value (from XML update command or from query string)
+  // into the internal format.
+  // - used in delete when a Term needs to be created.
+  // - used by the default getTokenizer() and createField()
+  public String toInternal(String val) {
+    return val;
+  }
+
+  // Convert the stored-field format to an external (string, human readable) value
+  // currently used in writing XML of the search result (but perhaps
+  // a more efficient toXML(Field f, Writer w) should be used
+  // in the future.
+  public String toExternal(Field f) {
+    return f.stringValue();
+  }
+
+
+  public String indexedToReadable(String indexedForm) {
+    return indexedForm;
+  }
+
+
+  /*********
+  // default analyzer for non-text fields.
+  // Only reads 80 bytes, but that should be plenty for a single value.
+  public Analyzer getAnalyzer() {
+    if (analyzer != null) return analyzer;
+
+    // the default analyzer...
+    return new Analyzer() {
+      public TokenStream tokenStream(String fieldName, Reader reader) {
+        return new Tokenizer(reader) {
+          final char[] cbuf = new char[80];
+          public Token next() throws IOException {
+            int n = input.read(cbuf,0,80);
+            if (n<=0) return null;
+            String s = toInternal(new String(cbuf,0,n));
+            return new Token(s,0,n);
+          };
+        };
+      }
+    };
+  }
+  **********/
+
+
+  //
+  // Default analyzer for types that only produce 1 verbatim token...
+  // A maximum size of chars to be read must be specified
+  //
+  protected final class DefaultAnalyzer extends Analyzer {
+    final int maxChars;
+
+    DefaultAnalyzer(int maxChars) {
+      this.maxChars=maxChars;
+    }
+
+    public TokenStream tokenStream(String fieldName, Reader reader) {
+      return new Tokenizer(reader) {
+        char[] cbuf = new char[maxChars];
+        public Token next() throws IOException {
+          int n = input.read(cbuf,0,maxChars);
+          if (n<=0) return null;
+          String s = toInternal(new String(cbuf,0,n));  // virtual func on parent
+          return new Token(s,0,n);
+        };
+      };
+    }
+
+    public int getPositionIncrementGap(String fieldName) {
+      return positionIncrementGap;
+    }
+  }
+
+
+  //analyzer set by schema for text types.
+  //subclasses can set analyzer themselves or override getAnalyzer()
+  protected Analyzer analyzer=new DefaultAnalyzer(256);
+  protected Analyzer queryAnalyzer=analyzer;
+
+  // get analyzer should be fast to call... since the addition of dynamic fields,
+  // this can be called all the time instead of just once at startup.
+  // The analyzer will only be used in the following scenarios:
+  // - during a document add for any field that has "tokenized" set (typically
+  //   only Text fields)
+  // - during query parsing
+
+  public Analyzer getAnalyzer() {
+    return analyzer;
+  }
+
+  public Analyzer getQueryAnalyzer() {
+    return queryAnalyzer;
+  }
+
+  // This is called by the schema parser if a custom analyzer is defined
+  public void setAnalyzer(Analyzer analyzer) {
+    this.analyzer = analyzer;
+    log.finest("FieldType: " + typeName + ".setAnalyzer(" + analyzer.getClass().getName() + ")" );
+  }
+
+   // This is called by the schema parser if a custom analyzer is defined
+  public void setQueryAnalyzer(Analyzer analyzer) {
+    this.queryAnalyzer = analyzer;
+    log.finest("FieldType: " + typeName + ".setQueryAnalyzer(" + analyzer.getClass().getName() + ")" );
+  }
+
+
+  public abstract void write(XMLWriter xmlWriter, String name, Field f) throws IOException;
+
+
+  public abstract SortField getSortField(SchemaField field, boolean top);
+
+  protected SortField getStringSort(SchemaField field, boolean reverse) {
+    return Sorting.getStringSortField(field.name, reverse, field.sortMissingLast(),field.sortMissingFirst());
+  }
+
+  /** called to get the default value source (normally, from the
+   *  Lucene FieldCache.)
+   */
+  public ValueSource getValueSource(SchemaField field) {
+    return new OrdFieldSource(field.name);
+  }
+}

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/FieldType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/FloatField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/FloatField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/FloatField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/FloatField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.function.ValueSource;
+import org.apache.lucene.search.function.FloatFieldSource;
+import org.apache.lucene.document.Field;
+import org.apache.solr.request.XMLWriter;
+
+import java.util.Map;
+import java.io.IOException;
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public class FloatField extends FieldType {
+  protected void init(IndexSchema schema, Map<String,String> args) {
+    restrictProps(SORT_MISSING_FIRST | SORT_MISSING_LAST);
+  }
+
+  public SortField getSortField(SchemaField field,boolean reverse) {
+    return new SortField(field.name,SortField.FLOAT, reverse);
+  }
+
+  public ValueSource getValueSource(SchemaField field) {
+    return new FloatFieldSource(field.name);
+  }
+
+
+  public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+    xmlWriter.writeFloat(name, f.stringValue());
+  }
+}

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/FloatField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,542 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.search.DefaultSimilarity;
+import org.apache.lucene.search.Similarity;
+import org.apache.solr.core.SolrException;
+import org.apache.solr.core.Config;
+import org.apache.solr.analysis.TokenFilterFactory;
+import org.apache.solr.analysis.TokenizerChain;
+import org.apache.solr.analysis.TokenizerFactory;
+import org.apache.solr.util.DOMUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.*;
+import java.util.logging.Logger;
+
+/**
+ * <code>IndexSchema</code> contains information about the valid fields in an index
+ * and the types of those fields.
+ *
+ * @author yonik
+ * @version $Id: IndexSchema.java,v 1.21 2005/12/20 16:05:46 yonik Exp $
+ */
+
+public final class IndexSchema {
+  final static Logger log = Logger.getLogger(IndexSchema.class.getName());
+
+  private final String schemaFile;
+  private String name;
+  private float version;
+
+  public IndexSchema(String schemaFile) {
+    this.schemaFile=schemaFile;
+    readConfig();
+  }
+
+  public InputStream getInputStream() {
+    return Config.openResource(schemaFile);
+  }
+
+
+  float getVersion() {
+    return version;
+  }
+
+  public String getName() { return name; }
+
+  private final HashMap<String, SchemaField> fields = new HashMap<String,SchemaField>();
+  private final HashMap<String, FieldType> fieldTypes = new HashMap<String,FieldType>();
+
+  public Map<String,SchemaField> getFields() { return fields; }
+  public Map<String,FieldType> getFieldTypes() { return fieldTypes; }
+
+
+  private Similarity similarity;
+  public Similarity getSimilarity() { return similarity; }
+
+  private Analyzer analyzer;
+  public Analyzer getAnalyzer() { return analyzer; }
+
+  private Analyzer queryAnalyzer;
+  public Analyzer getQueryAnalyzer() { return queryAnalyzer; }
+
+  private String defaultSearchFieldName=null;
+  public String getDefaultSearchFieldName() {
+    return defaultSearchFieldName;
+  }
+
+  private SchemaField uniqueKeyField;
+  public SchemaField getUniqueKeyField() { return uniqueKeyField; }
+
+  private String uniqueKeyFieldName;
+  private FieldType uniqueKeyFieldType;
+
+  public Field getUniqueKeyField(org.apache.lucene.document.Document doc) {
+    return doc.getField(uniqueKeyFieldName);  // this should return null if name is null
+  }
+
+  public String printableUniqueKey(org.apache.lucene.document.Document doc) {
+     Field f = doc.getField(uniqueKeyFieldName);
+     return f==null ? null : uniqueKeyFieldType.toExternal(f);
+  }
+
+  private SchemaField getIndexedField(String fname) {
+    SchemaField f = getFields().get(fname);
+    if (f==null) {
+      throw new RuntimeException("unknown field '" + fname + "'");
+    }
+    if (!f.indexed()) {
+      throw new RuntimeException("'"+fname+"' is not an indexed field:" + f);
+    }
+    return f;
+  }
+
+
+
+  private class SolrAnalyzer extends Analyzer {
+    protected final HashMap<String,Analyzer> analyzers;
+
+    SolrAnalyzer() {
+      analyzers = analyzerCache();
+    }
+
+    protected HashMap<String,Analyzer> analyzerCache() {
+      HashMap<String,Analyzer> cache = new HashMap<String,Analyzer>();
+       for (SchemaField f : getFields().values()) {
+        Analyzer analyzer = f.getType().getAnalyzer();
+        cache.put(f.getName(), analyzer);
+      }
+      return cache;
+    }
+
+    protected Analyzer getAnalyzer(String fieldName)
+    {
+      Analyzer analyzer = analyzers.get(fieldName);
+      return analyzer!=null ? analyzer : getDynamicFieldType(fieldName).getAnalyzer();
+    }
+
+    public TokenStream tokenStream(String fieldName, Reader reader)
+    {
+      return getAnalyzer(fieldName).tokenStream(fieldName,reader);
+    }
+
+    public int getPositionIncrementGap(String fieldName) {
+      return getAnalyzer(fieldName).getPositionIncrementGap(fieldName);
+    }
+  }
+
+
+  private class SolrQueryAnalyzer extends SolrAnalyzer {
+    protected HashMap<String,Analyzer> analyzerCache() {
+      HashMap<String,Analyzer> cache = new HashMap<String,Analyzer>();
+       for (SchemaField f : getFields().values()) {
+        Analyzer analyzer = f.getType().getQueryAnalyzer();
+        cache.put(f.getName(), analyzer);
+      }
+      return cache;
+    }
+
+    protected Analyzer getAnalyzer(String fieldName)
+    {
+      Analyzer analyzer = analyzers.get(fieldName);
+      return analyzer!=null ? analyzer : getDynamicFieldType(fieldName).getQueryAnalyzer();
+    }
+  }
+
+
+  private void readConfig() {
+    log.info("Reading Solr Schema");
+
+    try {
+      /***
+      DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+      Document document = builder.parse(getInputStream());
+      ***/
+
+      Config config = new Config("schema", getInputStream(), "/schema/");
+      Document document = config.getDocument();
+      XPath xpath = config.getXPath();
+
+      Node nd = (Node) xpath.evaluate("/schema/@name", document, XPathConstants.NODE);
+      if (nd==null) {
+        log.warning("schema has no name!");
+      } else {
+        name = nd.getNodeValue();
+        log.info("Schema name=" + name);
+      }
+
+      version = config.getFloat("/schema/@version", 1.0f);
+
+      String expression = "/schema/types/fieldtype";
+      NodeList nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
+
+
+      for (int i=0; i<nodes.getLength(); i++) {
+        Node node = nodes.item(i);
+        NamedNodeMap attrs = node.getAttributes();
+
+        String name = DOMUtil.getAttr(attrs,"name","fieldtype error");
+        log.finest("reading fieldtype "+name);
+        String clsName = DOMUtil.getAttr(attrs,"class", "fieldtype error");
+        FieldType ft = (FieldType)Config.newInstance(clsName);
+        ft.setTypeName(name);
+
+        expression = "./analyzer[@type='query']";
+        Node anode = (Node)xpath.evaluate(expression, node, XPathConstants.NODE);
+        Analyzer queryAnalyzer = readAnalyzer(anode);
+
+        // An analyzer without a type specified, or with type="index"
+        expression = "./analyzer[not(@type)] | ./analyzer[@type='index']";
+        anode = (Node)xpath.evaluate(expression, node, XPathConstants.NODE);
+        Analyzer analyzer = readAnalyzer(anode);
+
+        if (queryAnalyzer==null) queryAnalyzer=analyzer;
+        if (analyzer==null) analyzer=queryAnalyzer;
+        if (analyzer!=null) {
+          ft.setAnalyzer(analyzer);
+          ft.setQueryAnalyzer(queryAnalyzer);
+        }
+
+
+        ft.setArgs(this, DOMUtil.toMapExcept(attrs,"name","class"));
+        fieldTypes.put(ft.typeName,ft);
+        log.finest("fieldtype defined: " + ft);
+      }
+
+
+      ArrayList<DynamicField> dFields = new ArrayList<DynamicField>();
+      expression = "/schema/fields/field | /schema/fields/dynamicField";
+      nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
+
+      for (int i=0; i<nodes.getLength(); i++) {
+        Node node = nodes.item(i);
+
+        NamedNodeMap attrs = node.getAttributes();
+
+        String name = DOMUtil.getAttr(attrs,"name","field definition");
+        log.finest("reading field def "+name);
+        String type = DOMUtil.getAttr(attrs,"type","field " + name);
+        String val;
+
+        FieldType ft = fieldTypes.get(type);
+        if (ft==null) {
+          throw new SolrException(400,"Unknown fieldtype '" + type + "'",false);
+        }
+
+        Map<String,String> args = DOMUtil.toMapExcept(attrs, "name", "type");
+
+        SchemaField f = SchemaField.create(name,ft,args);
+
+        if (node.getNodeName().equals("field")) {
+          fields.put(f.getName(),f);
+          log.fine("field defined: " + f);
+        } else if (node.getNodeName().equals("dynamicField")) {
+          dFields.add(new DynamicField(f));
+          log.fine("dynamic field defined: " + f);
+        } else {
+          // we should never get here
+          throw new RuntimeException("Unknown field type");
+        }
+      }
+
+    // OK, now sort the dynamic fields largest to smallest size so we don't get
+    // any false matches.  We want to act like a compiler tool and try and match
+    // the largest string possible.
+    Collections.sort(dFields, new Comparator<DynamicField>() {
+        public int compare(DynamicField a, DynamicField b) {
+           // swap natural ordering to get biggest first.
+           // The sort is stable, so elements of the same size should
+           // be
+           if (a.regex.length() < b.regex.length()) return 1;
+           else if (a.regex.length() > b.regex.length()) return -1;
+           return 0;
+        }
+      }
+    );
+
+    log.finest("Dynamic Field Ordering:" + dFields);
+
+    // stuff it in a normal array for faster access
+    dynamicFields = (DynamicField[])dFields.toArray(new DynamicField[dFields.size()]);
+
+
+    Node node = (Node) xpath.evaluate("/schema/similarity/@class", document, XPathConstants.NODE);
+    if (node==null) {
+      similarity = new DefaultSimilarity();
+      log.fine("using default similarity");
+    } else {
+      similarity = (Similarity)Config.newInstance(node.getNodeValue().trim());
+      log.fine("using similarity " + similarity.getClass().getName());
+    }
+
+    node = (Node) xpath.evaluate("/schema/defaultSearchField/text()", document, XPathConstants.NODE);
+    if (node==null) {
+      log.warning("no default search field specified in schema.");
+    } else {
+      String defName=node.getNodeValue().trim();
+      defaultSearchFieldName = getIndexedField(defName)!=null ? defName : null;
+      log.info("default search field is "+defName);
+    }
+
+    node = (Node) xpath.evaluate("/schema/uniqueKey/text()", document, XPathConstants.NODE);
+    if (node==null) {
+      log.warning("no uniqueKey specified in schema.");
+    } else {
+      uniqueKeyField=getIndexedField(node.getNodeValue().trim());
+      uniqueKeyFieldName=uniqueKeyField.getName();
+      uniqueKeyFieldType=uniqueKeyField.getType();
+      log.info("unique key field: "+uniqueKeyFieldName);
+    }
+
+    /////////////// parse out copyField commands ///////////////
+    // Map<String,ArrayList<SchemaField>> cfields = new HashMap<String,ArrayList<SchemaField>>();
+    // expression = "/schema/copyField";
+    expression = "//copyField";
+    nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
+
+      for (int i=0; i<nodes.getLength(); i++) {
+        node = nodes.item(i);
+        NamedNodeMap attrs = node.getAttributes();
+
+        String source = DOMUtil.getAttr(attrs,"source","copyField definition");
+        String dest = DOMUtil.getAttr(attrs,"dest","copyField definition");
+        log.fine("copyField source='"+source+"' dest='"+dest+"'");
+        SchemaField f = getField(source);
+        SchemaField d = getField(dest);
+        SchemaField[] destArr = copyFields.get(source);
+        if (destArr==null) {
+          destArr=new SchemaField[]{d};
+        } else {
+          destArr = (SchemaField[])append(destArr,d);
+        }
+        copyFields.put(source,destArr);
+      }
+
+
+    } catch (SolrException e) {
+      throw e;
+    } catch(Exception e) {
+      // unexpected exception...
+      throw new SolrException(1,"Schema Parsing Failed",e,false);
+    }
+
+     analyzer = new SolrAnalyzer();
+     queryAnalyzer = new SolrQueryAnalyzer();
+  }
+
+  private static Object[] append(Object[] orig, Object item) {
+    Object[] newArr = (Object[])java.lang.reflect.Array.newInstance(orig.getClass().getComponentType(), orig.length+1);
+	  System.arraycopy(orig, 0, newArr, 0, orig.length);
+    newArr[orig.length] = item;
+    return newArr;
+  }
+
+  //
+  // <analyzer><tokenizer class="...."/><tokenizer class="...." arg="....">
+  //
+  //
+  private Analyzer readAnalyzer(Node node) throws XPathExpressionException {
+    // parent node used to be passed in as "fieldtype"
+    // if (!fieldtype.hasChildNodes()) return null;
+    // Node node = DOMUtil.getChild(fieldtype,"analyzer");
+
+    if (node == null) return null;
+    NamedNodeMap attrs = node.getAttributes();
+    String analyzerName = DOMUtil.getAttr(attrs,"class");
+    if (analyzerName != null) {
+      return (Analyzer)Config.newInstance(analyzerName);
+    }
+
+    XPath xpath = XPathFactory.newInstance().newXPath();
+    Node tokNode = (Node)xpath.evaluate("./tokenizer", node, XPathConstants.NODE);
+    NodeList nList = (NodeList)xpath.evaluate("./filter", node, XPathConstants.NODESET);
+
+    if (tokNode==null){
+      throw new SolrException(1,"analyzer without class or tokenizer & filter list");
+    }
+    TokenizerFactory tfac = readTokenizerFactory(tokNode);
+
+    /******
+    // oops, getChildNodes() includes text (newlines, etc) in addition
+    // to the actual child elements
+    NodeList nList = node.getChildNodes();
+    TokenizerFactory tfac = readTokenizerFactory(nList.item(0));
+     if (tfac==null) {
+       throw new SolrException(1,"TokenizerFactory must be specified first in analyzer");
+     }
+    ******/
+
+    ArrayList<TokenFilterFactory> filters = new ArrayList<TokenFilterFactory>();
+    for (int i=0; i<nList.getLength(); i++) {
+      TokenFilterFactory filt = readTokenFilterFactory(nList.item(i));
+      if (filt != null) filters.add(filt);
+    }
+
+    return new TokenizerChain(tfac, filters.toArray(new TokenFilterFactory[filters.size()]));
+  };
+
+  // <tokenizer class="solr.StandardFilterFactory"/>
+  private TokenizerFactory readTokenizerFactory(Node node) {
+    // if (node.getNodeName() != "tokenizer") return null;
+    NamedNodeMap attrs = node.getAttributes();
+    String className = DOMUtil.getAttr(attrs,"class","tokenizer");
+    TokenizerFactory tfac = (TokenizerFactory)Config.newInstance(className);
+    tfac.init(DOMUtil.toMapExcept(attrs,"class"));
+    return tfac;
+  }
+
+  // <tokenizer class="solr.StandardFilterFactory"/>
+  private TokenFilterFactory readTokenFilterFactory(Node node) {
+    // if (node.getNodeName() != "filter") return null;
+    NamedNodeMap attrs = node.getAttributes();
+    String className = DOMUtil.getAttr(attrs,"class","token filter");
+    TokenFilterFactory tfac = (TokenFilterFactory)Config.newInstance(className);
+    tfac.init(DOMUtil.toMapExcept(attrs,"class"));
+    return tfac;
+  }
+
+
+  //
+  // Instead of storing a type, this could be implemented as a hierarchy
+  // with a virtual matches().
+  // Given how often a search will be done, however, speed is the overriding
+  // concern and I'm not sure which is faster.
+  //
+  final static class DynamicField {
+    final static int STARTS_WITH=1;
+    final static int ENDS_WITH=2;
+
+    final String regex;
+    final int type;
+    final SchemaField prototype;
+
+    final String str;
+
+    DynamicField(SchemaField prototype) {
+      this.regex=prototype.name;
+      if (regex.startsWith("*")) {
+        type=ENDS_WITH;
+        str=regex.substring(1);
+      }
+      else if (regex.endsWith("*")) {
+        type=STARTS_WITH;
+        str=regex.substring(0,regex.length()-1);
+      }
+      else {
+        throw new RuntimeException("dynamic field name must start or end with *");
+      }
+      this.prototype=prototype;
+    }
+
+    boolean matches(String name) {
+      if (type==STARTS_WITH && name.startsWith(str)) return true;
+      else if (type==ENDS_WITH && name.endsWith(str)) return true;
+      else return false;
+    }
+
+    SchemaField makeSchemaField(String name) {
+      // could have a cache instead of returning a new one each time, but it might
+      // not be worth it.
+      // Actually, a higher level cache could be worth it to avoid too many
+      // .startsWith() and .endsWith() comparisons.  it depends on how many
+      // dynamic fields there are.
+      return new SchemaField(prototype, name);
+    }
+
+    public String toString() {
+      return prototype.toString();
+    }
+  }
+
+
+
+  private DynamicField[] dynamicFields;
+
+
+  // get a field, and if not statically defined, check dynamic fields.
+  public SchemaField getField(String fieldName) {
+     SchemaField f = fields.get(fieldName);
+    if (f != null) return f;
+
+    for (DynamicField df : dynamicFields) {
+      if (df.matches(fieldName)) return df.makeSchemaField(fieldName);
+    }
+
+    // Hmmm, default field could also be implemented with a dynamic field of "*".
+    // It would have to be special-cased and only used if nothing else matched.
+    /***  REMOVED -YCS
+    if (defaultFieldType != null) return new SchemaField(fieldName,defaultFieldType);
+    ***/
+    throw new SolrException(1,"undefined field "+fieldName);
+  }
+
+  // This method exists because it can be more efficient for dynamic fields
+  // if a full SchemaField isn't needed.
+  public FieldType getFieldType(String fieldName) {
+    SchemaField f = fields.get(fieldName);
+    if (f != null) return f.getType();
+
+    return getDynamicFieldType(fieldName);
+  }
+
+  /**
+   * return null instead of throwing an exception if
+   * the field is undefined.
+   */
+  public FieldType getFieldTypeNoEx(String fieldName) {
+    SchemaField f = fields.get(fieldName);
+    if (f != null) return f.getType();
+    return dynFieldType(fieldName);
+  }
+
+
+  public FieldType getDynamicFieldType(String fieldName) {
+     for (DynamicField df : dynamicFields) {
+      if (df.matches(fieldName)) return df.prototype.getType();
+    }
+    throw new SolrException(400,"undefined field "+fieldName);
+  }
+
+  private FieldType dynFieldType(String fieldName) {
+     for (DynamicField df : dynamicFields) {
+      if (df.matches(fieldName)) return df.prototype.getType();
+    }
+    return null;
+  };
+
+
+  private final Map<String, SchemaField[]> copyFields = new HashMap<String,SchemaField[]>();
+  public SchemaField[] getCopyFields(String sourceField) {
+    return copyFields.get(sourceField);
+  }
+
+}
+

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/IntField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/IntField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/IntField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/IntField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,47 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.function.ValueSource;
+import org.apache.lucene.search.function.IntFieldSource;
+import org.apache.lucene.document.Field;
+import org.apache.solr.request.XMLWriter;
+
+import java.util.Map;
+import java.io.IOException;
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public class IntField extends FieldType {
+  protected void init(IndexSchema schema, Map<String,String> args) {
+    restrictProps(SORT_MISSING_FIRST | SORT_MISSING_LAST);
+  }
+
+  public SortField getSortField(SchemaField field,boolean reverse) {
+    return new SortField(field.name,SortField.INT, reverse);
+  }
+
+  public ValueSource getValueSource(SchemaField field) {
+    return new IntFieldSource(field.name);
+  }
+
+  public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+    xmlWriter.writeInt(name, f.stringValue());
+  }
+}

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/IntField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/LongField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/LongField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/LongField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/LongField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,52 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.function.ValueSource;
+import org.apache.lucene.search.function.IntFieldSource;
+import org.apache.lucene.document.Field;
+import org.apache.solr.request.XMLWriter;
+
+import java.util.Map;
+import java.io.IOException;
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public class LongField extends FieldType {
+  protected void init(IndexSchema schema, Map<String,String> args) {
+    restrictProps(SORT_MISSING_FIRST | SORT_MISSING_LAST);
+  }
+
+  /////////////////////////////////////////////////////////////
+  // TODO: ACK.. there is no SortField.LONG!
+  public SortField getSortField(SchemaField field,boolean reverse) {
+    // todo - log warning
+    return new SortField(field.name,SortField.INT, reverse);
+  }
+
+  public ValueSource getValueSource(SchemaField field) {
+    // todo - log warning
+    return new IntFieldSource(field.name);
+  }
+
+
+  public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+    xmlWriter.writeLong(name, f.stringValue());
+  }
+}

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/LongField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/SchemaField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/SchemaField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/SchemaField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/SchemaField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,159 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.lucene.document.Field;
+import org.apache.lucene.search.SortField;
+import org.apache.solr.request.XMLWriter;
+
+import java.util.Map;
+import java.io.IOException;
+
+/**
+ * @author yonik
+ * @version $Id: SchemaField.java,v 1.8 2005/11/28 06:03:19 yonik Exp $
+ */
+
+
+
+public final class SchemaField extends FieldProperties {
+  final String name;
+  final FieldType type;
+  final int properties;
+
+
+  /** Create a new SchemaField with the given name and type,
+   *  using all the default properties from the type.
+   */
+  public SchemaField(String name, FieldType type) {
+    this(name, type, type.properties);
+  }
+
+  /** Create a new SchemaField from an existing one by using all
+   * of the properties of the prototype except the field name.
+   */
+  public SchemaField(SchemaField prototype, String name) {
+    this(name, prototype.type, prototype.properties);
+  }
+
+ /** Create a new SchemaField with the given name and type,
+   * and with the specified properties.  Properties are *not*
+   * inherited from the type in this case, so users of this
+   * constructor should derive the properties from type.getProperties()
+   *  using all the default properties from the type.
+   */
+  public SchemaField(String name, FieldType type, int properties) {
+    this.name = name;
+    this.type = type;
+    this.properties = properties;
+  }
+
+  public String getName() { return name; }
+  public FieldType getType() { return type; }
+  int getProperties() { return properties; }
+
+  public boolean indexed() { return (properties & INDEXED)!=0; }
+  public boolean stored() { return (properties & STORED)!=0; }
+  public boolean storeTermVector() { return (properties & STORE_TERMVECTORS)!=0; }
+  public boolean storeTermPositions() { return (properties & STORE_TERMPOSITIONS)!=0; }
+  public boolean storeTermOffsets() { return (properties & STORE_TERMOFFSETS)!=0; }
+  public boolean omitNorms() { return (properties & OMIT_NORMS)!=0; }
+  public boolean multiValued() { return (properties & MULTIVALUED)!=0; }
+  public boolean sortMissingFirst() { return (properties & SORT_MISSING_FIRST)!=0; }
+  public boolean sortMissingLast() { return (properties & SORT_MISSING_LAST)!=0; }
+
+  // things that should be determined by field type, not set as options
+  boolean isTokenized() { return (properties & TOKENIZED)!=0; }
+  boolean isBinary() { return (properties & BINARY)!=0; }
+  boolean isCompressed() { return (properties & COMPRESSED)!=0; }
+
+  public Field createField(String val, float boost) {
+    return type.createField(this,val,boost);
+  }
+
+  public String toString() {
+    return name + "{type="+type.getTypeName()
+            + ",properties=" + propertiesToString(properties)
+            + "}";
+  }
+
+  public void write(XMLWriter writer, String name, Field val) throws IOException {
+    // name is passed in because it may be null if name should not be used.
+    type.write(writer,name,val);
+  }
+
+  public SortField getSortField(boolean top) {
+    return type.getSortField(this, top);
+  }
+
+
+  static SchemaField create(String name, FieldType ft, Map props) {
+    int trueProps = parseProperties(props,true);
+    int falseProps = parseProperties(props,false);
+
+    int p = ft.properties;
+
+    //
+    // If any properties were explicitly turned off, then turn off other properties
+    // that depend on that.
+    //
+    if (on(falseProps,STORED)) {
+      int pp = STORED | BINARY | COMPRESSED;
+      if (on(pp,trueProps)) {
+        throw new RuntimeException("SchemaField: " + name + " conflicting stored field options:" + props);
+      }
+      p &= ~pp;
+    }
+
+    if (on(falseProps,INDEXED)) {
+      int pp = (INDEXED | OMIT_NORMS
+              | STORE_TERMVECTORS | STORE_TERMPOSITIONS | STORE_TERMOFFSETS
+              | SORT_MISSING_FIRST | SORT_MISSING_LAST);
+      if (on(pp,trueProps)) {
+        throw new RuntimeException("SchemaField: " + name + " conflicting indexed field options:" + props);
+      }
+      p &= ~pp;
+
+    }
+
+    if (on(falseProps,STORE_TERMVECTORS)) {
+      int pp = (STORE_TERMVECTORS | STORE_TERMPOSITIONS | STORE_TERMOFFSETS);
+      if (on(pp,trueProps)) {
+        throw new RuntimeException("SchemaField: " + name + " conflicting termvector field options:" + props);
+      }
+      p &= ~pp;
+    }
+
+    // override sort flags
+    if (on(trueProps,SORT_MISSING_FIRST)) {
+      p &= ~SORT_MISSING_LAST;
+    }
+
+    if (on(trueProps,SORT_MISSING_LAST)) {
+      p &= ~SORT_MISSING_FIRST;
+    }
+
+    p &= ~falseProps;
+    p |= trueProps;
+
+    return new SchemaField(name, ft, p);
+  }
+}
+
+
+
+

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/SchemaField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/solr/trunk/src/java/org/apache/solr/schema/SortableDoubleField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/SortableDoubleField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/SortableDoubleField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/SortableDoubleField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,132 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.schema;
+
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.FieldCache;
+import org.apache.lucene.search.function.ValueSource;
+import org.apache.lucene.search.function.FieldCacheSource;
+import org.apache.lucene.search.function.DocValues;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.IndexReader;
+import org.apache.solr.util.NumberUtils;
+import org.apache.solr.request.XMLWriter;
+
+import java.util.Map;
+import java.io.IOException;
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public class SortableDoubleField extends FieldType {
+  protected void init(IndexSchema schema, Map<String,String> args) {
+  }
+
+  public SortField getSortField(SchemaField field,boolean reverse) {
+    return getStringSort(field,reverse);
+  }
+
+  public ValueSource getValueSource(SchemaField field) {
+    return new SortableDoubleFieldSource(field.name);
+  }
+
+  public String toInternal(String val) {
+    return NumberUtils.double2sortableStr(val);
+  }
+
+  public String toExternal(Field f) {
+    return indexedToReadable(f.stringValue());
+  }
+
+  public String indexedToReadable(String indexedForm) {
+    return NumberUtils.SortableStr2doubleStr(indexedForm);
+  }
+
+  public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+    String sval = f.stringValue();
+    xmlWriter.writeDouble(name, NumberUtils.SortableStr2double(sval));
+  }
+}
+
+
+
+
+class SortableDoubleFieldSource extends FieldCacheSource {
+  protected double defVal;
+
+  public SortableDoubleFieldSource(String field) {
+    this(field, 0.0);
+  }
+
+  public SortableDoubleFieldSource(String field, double defVal) {
+    super(field);
+    this.defVal = defVal;
+  }
+
+  public String description() {
+    return "sdouble(" + field + ')';
+  }
+
+  public DocValues getValues(IndexReader reader) throws IOException {
+    final FieldCache.StringIndex index = cache.getStringIndex(reader, field);
+    final int[] order = index.order;
+    final String[] lookup = index.lookup;
+    final double def = defVal;
+
+    return new DocValues() {
+      public float floatVal(int doc) {
+        return (float)doubleVal(doc);
+      }
+
+      public int intVal(int doc) {
+        return (int)doubleVal(doc);
+      }
+
+      public long longVal(int doc) {
+        return (long)doubleVal(doc);
+      }
+
+      public double doubleVal(int doc) {
+        int ord=order[doc];
+        return ord==0 ? def  : NumberUtils.SortableStr2double(lookup[ord]);
+      }
+
+      public String strVal(int doc) {
+        return Double.toString(doubleVal(doc));
+      }
+
+      public String toString(int doc) {
+        return description() + '=' + doubleVal(doc);
+      }
+    };
+  }
+
+  public boolean equals(Object o) {
+    return o instanceof SortableDoubleFieldSource
+            && super.equals(o)
+            && defVal == ((SortableDoubleFieldSource)o).defVal;
+  }
+
+  private static int hcode = SortableDoubleFieldSource.class.hashCode();
+  public int hashCode() {
+    long bits = Double.doubleToLongBits(defVal);
+    int ibits = (int)(bits ^ (bits>>>32));  // mix upper bits into lower.
+    return hcode + super.hashCode() + ibits;
+  };
+}
+
+

Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/SortableDoubleField.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message