You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-commits@lucene.apache.org by yo...@apache.org on 2006/01/26 06:40:05 UTC
svn commit: r372455 [6/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...
Added: incubator/solr/trunk/src/java/org/apache/solr/schema/SortableFloatField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/SortableFloatField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/SortableFloatField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/SortableFloatField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,129 @@
+/**
+ * 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 SortableFloatField 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 SortableFloatFieldSource(field.name);
+ }
+
+ public String toInternal(String val) {
+ return NumberUtils.float2sortableStr(val);
+ }
+
+ public String toExternal(Field f) {
+ return indexedToReadable(f.stringValue());
+ }
+
+ public String indexedToReadable(String indexedForm) {
+ return NumberUtils.SortableStr2floatStr(indexedForm);
+ }
+
+ public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+ String sval = f.stringValue();
+ xmlWriter.writeFloat(name, NumberUtils.SortableStr2float(sval));
+ }
+}
+
+
+
+
+class SortableFloatFieldSource extends FieldCacheSource {
+ protected float defVal;
+
+ public SortableFloatFieldSource(String field) {
+ this(field, 0.0f);
+ }
+
+ public SortableFloatFieldSource(String field, float defVal) {
+ super(field);
+ this.defVal = defVal;
+ }
+
+ public String description() {
+ return "sfloat(" + 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 float def = defVal;
+
+ return new DocValues() {
+ public float floatVal(int doc) {
+ int ord=order[doc];
+ return ord==0 ? def : NumberUtils.SortableStr2float(lookup[ord]);
+ }
+
+ public int intVal(int doc) {
+ return (int)floatVal(doc);
+ }
+
+ public long longVal(int doc) {
+ return (long)floatVal(doc);
+ }
+
+ public double doubleVal(int doc) {
+ return (double)floatVal(doc);
+ }
+
+ public String strVal(int doc) {
+ return Float.toString(floatVal(doc));
+ }
+
+ public String toString(int doc) {
+ return description() + '=' + floatVal(doc);
+ }
+ };
+ }
+
+ public boolean equals(Object o) {
+ return o instanceof SortableFloatFieldSource
+ && super.equals(o)
+ && defVal == ((SortableFloatFieldSource)o).defVal;
+ }
+
+ private static int hcode = SortableFloatFieldSource.class.hashCode();
+ public int hashCode() {
+ return hcode + super.hashCode() + Float.floatToIntBits(defVal);
+ };
+}
+
Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/SortableFloatField.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/schema/SortableIntField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/SortableIntField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/SortableIntField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/SortableIntField.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 SortableIntField 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 SortableIntFieldSource(field.name);
+ }
+
+ public String toInternal(String val) {
+ // special case single digits? years?, etc
+ // stringCache? general stringCache on a
+ // global field level?
+ return NumberUtils.int2sortableStr(val);
+ }
+
+ public String toExternal(Field f) {
+ return indexedToReadable(f.stringValue());
+ }
+
+ public String indexedToReadable(String indexedForm) {
+ return NumberUtils.SortableStr2int(indexedForm);
+ }
+
+ public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+ String sval = f.stringValue();
+ // since writeInt an int instead of a String since that may be more efficient
+ // in the future (saves the construction of one String)
+ xmlWriter.writeInt(name, NumberUtils.SortableStr2int(sval,0,sval.length()));
+ }
+}
+
+
+
+class SortableIntFieldSource extends FieldCacheSource {
+ protected int defVal;
+
+ public SortableIntFieldSource(String field) {
+ this(field, 0);
+ }
+
+ public SortableIntFieldSource(String field, int defVal) {
+ super(field);
+ this.defVal = defVal;
+ }
+
+ public String description() {
+ return "sint(" + 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 int def = defVal;
+
+ return new DocValues() {
+ public float floatVal(int doc) {
+ return (float)intVal(doc);
+ }
+
+ public int intVal(int doc) {
+ int ord=order[doc];
+ return ord==0 ? def : NumberUtils.SortableStr2int(lookup[ord],0,3);
+ }
+
+ public long longVal(int doc) {
+ return (long)intVal(doc);
+ }
+
+ public double doubleVal(int doc) {
+ return (double)intVal(doc);
+ }
+
+ public String strVal(int doc) {
+ return Integer.toString(intVal(doc));
+ }
+
+ public String toString(int doc) {
+ return description() + '=' + intVal(doc);
+ }
+ };
+ }
+
+ public boolean equals(Object o) {
+ return o instanceof SortableIntFieldSource
+ && super.equals(o)
+ && defVal == ((SortableIntFieldSource)o).defVal;
+ }
+
+ private static int hcode = SortableIntFieldSource.class.hashCode();
+ public int hashCode() {
+ return hcode + super.hashCode() + defVal;
+ };
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/SortableIntField.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/schema/SortableLongField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/SortableLongField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/SortableLongField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/SortableLongField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,129 @@
+/**
+ * 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 SortableLongField 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 SortableLongFieldSource(field.name);
+ }
+
+ public String toInternal(String val) {
+ return NumberUtils.long2sortableStr(val);
+ }
+
+ public String indexedToReadable(String indexedForm) {
+ return NumberUtils.SortableStr2long(indexedForm);
+ }
+
+ public String toExternal(Field f) {
+ return indexedToReadable(f.stringValue());
+ }
+
+ public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+ String sval = f.stringValue();
+ xmlWriter.writeLong(name, NumberUtils.SortableStr2long(sval,0,sval.length()));
+ }
+}
+
+
+
+
+
+class SortableLongFieldSource extends FieldCacheSource {
+ protected long defVal;
+
+ public SortableLongFieldSource(String field) {
+ this(field, 0);
+ }
+
+ public SortableLongFieldSource(String field, long defVal) {
+ super(field);
+ this.defVal = defVal;
+ }
+
+ public String description() {
+ return "slong(" + 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 long def = defVal;
+
+ return new DocValues() {
+ public float floatVal(int doc) {
+ return (float)longVal(doc);
+ }
+
+ public int intVal(int doc) {
+ return (int)longVal(doc);
+ }
+
+ public long longVal(int doc) {
+ int ord=order[doc];
+ return ord==0 ? def : NumberUtils.SortableStr2long(lookup[ord],0,5);
+ }
+
+ public double doubleVal(int doc) {
+ return (double)longVal(doc);
+ }
+
+ public String strVal(int doc) {
+ return Long.toString(longVal(doc));
+ }
+
+ public String toString(int doc) {
+ return description() + '=' + longVal(doc);
+ }
+ };
+ }
+
+ public boolean equals(Object o) {
+ return o instanceof SortableLongFieldSource
+ && super.equals(o)
+ && defVal == ((SortableLongFieldSource)o).defVal;
+ }
+
+ private static int hcode = SortableLongFieldSource.class.hashCode();
+ public int hashCode() {
+ return hcode + super.hashCode() + (int)defVal;
+ };
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/SortableLongField.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/schema/StrField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/StrField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/StrField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/StrField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,41 @@
+/**
+ * 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.document.Field;
+import org.apache.solr.request.XMLWriter;
+
+import java.util.Map;
+import java.io.IOException;
+/**
+ * @author yonik
+ * @version $Id$
+ */
+//TODO: allow specification of max string size?
+public class StrField extends FieldType {
+ protected void init(IndexSchema schema, Map<String,String> args) {
+ }
+
+ public SortField getSortField(SchemaField field,boolean reverse) {
+ return getStringSort(field,reverse);
+ }
+
+ public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+ xmlWriter.writeStr(name, f.stringValue());
+ }
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/StrField.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/schema/TextField.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/schema/TextField.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/schema/TextField.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/schema/TextField.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,43 @@
+/**
+ * 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.document.Field;
+import org.apache.solr.request.XMLWriter;
+
+import java.util.Map;
+import java.io.IOException;
+
+/** <code>TextField</code> is the basic type for configurable text analysis.
+ * Analyzers for field types using this implementation should be defined in the schema.
+ * @author yonik
+ * @version $Id$
+ */
+public class TextField extends FieldType {
+ protected void init(IndexSchema schema, Map<String,String> args) {
+ properties |= TOKENIZED;
+ }
+
+ public SortField getSortField(SchemaField field, boolean reverse) {
+ return new SortField(field.name,SortField.STRING, reverse);
+ }
+
+ public void write(XMLWriter xmlWriter, String name, Field f) throws IOException {
+ xmlWriter.writeStr(name, f.stringValue());
+ }
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/schema/TextField.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/BitDocSet.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/BitDocSet.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/BitDocSet.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/BitDocSet.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,112 @@
+/**
+ * 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.search;
+
+import java.util.BitSet;
+
+/**
+ * <code>BitDocSet</code> represents an unordered set of Lucene Document Ids
+ * using a BitSet. A set bit represents inclusion in the set for that document.
+ *
+ * @author yonik
+ * @version $Id: BitDocSet.java,v 1.4 2005/10/27 04:14:49 yonik Exp $
+ * @since solr 0.9
+ */
+public class BitDocSet extends DocSetBase {
+ final BitSet bits;
+ int size; // number of docs in the set (cached for perf)
+
+ public BitDocSet() {
+ bits = new BitSet();
+ }
+
+ public BitDocSet(BitSet bits) {
+ this.bits = bits;
+ size=-1;
+ }
+
+ public BitDocSet(BitSet bits, int size) {
+ this.bits = bits;
+ this.size = size;
+ }
+
+ public DocIterator iterator() {
+ return new DocIterator() {
+ int pos=bits.nextSetBit(0);
+ public boolean hasNext() {
+ return pos>=0;
+ }
+
+ public Integer next() {
+ return nextDoc();
+ }
+
+ public void remove() {
+ bits.clear(pos);
+ }
+
+ public int nextDoc() {
+ int old=pos;
+ pos=bits.nextSetBit(old+1);
+ return old;
+ }
+
+ public float score() {
+ return 0.0f;
+ }
+ };
+ }
+
+ /**
+ *
+ * @return the <b>internal</b> BitSet that should <b>not</b> be modified.
+ */
+ public BitSet getBits() {
+ return bits;
+ }
+
+ public void add(int doc) {
+ bits.set(doc);
+ size=-1; // invalidate size
+ }
+
+ public void addUnique(int doc) {
+ size++;
+ bits.set(doc);
+ }
+
+ public int size() {
+ if (size!=-1) return size;
+ return size=bits.cardinality();
+ }
+
+ /**
+ * The number of set bits - size - is cached. If the bitset is changed externally,
+ * this method should be used to invalidate the previously cached size.
+ */
+ public void invalidateSize() {
+ size=-1;
+ }
+
+ public boolean exists(int doc) {
+ return bits.get(doc);
+ }
+
+ public long memSize() {
+ return (bits.size() >> 3) + 16;
+ }
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/BitDocSet.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/CacheConfig.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/CacheConfig.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/CacheConfig.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/CacheConfig.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,110 @@
+/**
+ * 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.search;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.Map;
+
+import org.apache.solr.util.DOMUtil;
+import org.apache.solr.core.SolrException;
+import org.apache.solr.core.SolrConfig;
+import org.apache.solr.core.Config;
+
+import javax.xml.xpath.XPathConstants;
+
+/**
+ * Contains the knowledge of how cache config is
+ * stored in the solarconfig.xml file, and implements a
+ * factory to create caches.
+ *
+ * @author yonik
+ * @version $Id: CacheConfig.java,v 1.2 2005/09/07 20:37:57 yonik Exp $
+ */
+class CacheConfig {
+ private String nodeName;
+ private Map args;
+
+ private String cacheImpl;
+ private Class clazz;
+
+ private Object[] persistence = new Object[1];
+
+ private String regenImpl;
+ private CacheRegenerator regenerator;
+
+ public CacheRegenerator getRegenerator() {
+ return regenerator;
+ }
+
+ public void setRegenerator(CacheRegenerator regenerator) {
+ this.regenerator = regenerator;
+ }
+
+ public static CacheConfig[] getMultipleConfigs(String configPath) {
+ NodeList nodes = (NodeList)SolrConfig.config.evaluate(configPath, XPathConstants.NODESET);
+ if (nodes==null || nodes.getLength()==0) return null;
+ CacheConfig[] configs = new CacheConfig[nodes.getLength()];
+ for (int i=0; i<nodes.getLength(); i++) {
+ configs[i] = getConfig(nodes.item(i));
+ }
+ return configs;
+ }
+
+
+ public static CacheConfig getConfig(String xpath) {
+ Node node = (Node)SolrConfig.config.getNode(xpath, false);
+ return getConfig(node);
+ }
+
+
+ public static CacheConfig getConfig(Node node) {
+ if (node==null) return null;
+ CacheConfig config = new CacheConfig();
+ config.nodeName = node.getNodeName();
+ config.args = DOMUtil.toMap(node.getAttributes());
+ String nameAttr = (String)config.args.get("name"); // OPTIONAL
+ if (nameAttr==null) {
+ config.args.put("name",config.nodeName);
+ }
+
+ config.cacheImpl = (String)config.args.get("class");
+ config.regenImpl = (String)config.args.get("regenerator");
+ config.clazz = Config.findClass(config.cacheImpl);
+ if (config.regenImpl != null) {
+ config.regenerator = (CacheRegenerator) Config.newInstance(config.regenImpl);
+ }
+
+
+ return config;
+ }
+
+ public SolrCache newInstance() {
+ try {
+ SolrCache cache = (SolrCache)clazz.newInstance();
+ persistence[0] = cache.init(args, persistence[0], regenerator);
+ return cache;
+ } catch (Exception e) {
+ SolrException.log(SolrCache.log,"Error instantiating cache",e);
+ // we can carry on without a cache... but should we?
+ // in some cases (like an OOM) we probably should try to continue.
+ return null;
+ }
+ }
+
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/CacheConfig.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/CacheRegenerator.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/CacheRegenerator.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/CacheRegenerator.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/CacheRegenerator.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,43 @@
+/**
+ * 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.search;
+
+import java.io.IOException;
+
+/**
+ * Implementations of <code>CacheRegenerator</code> are used in autowarming to populate a new cache
+ * based on an old cache. <code>regenerateItem</code> is called for each item that should be inserted into the new cache.
+ * <p>
+ * Implementations should have a noarg constructor and be thread safe (a single instance will be
+ * used for all cache autowarmings).
+ *
+ * @author yonik
+ * @version $Id: CacheRegenerator.java,v 1.2 2005/09/07 20:37:57 yonik Exp $
+ */
+public interface CacheRegenerator {
+ /**
+ * Regenerate an old cache item and insert it into <code>newCache</code>
+ *
+ * @param newSearcher the new searcher who's caches are being autowarmed
+ * @param newCache where regenerated cache items should be stored. the target of the autowarming
+ * @param oldCache the old cache being used as a source for autowarming
+ * @param oldKey the key of the old cache item to regenerate in the new cache
+ * @param oldVal the old value of the cache item
+ * @return true to continue with autowarming, false to stop
+ */
+ public boolean regenerateItem(SolrIndexSearcher newSearcher, SolrCache newCache, SolrCache oldCache, Object oldKey, Object oldVal) throws IOException;
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/CacheRegenerator.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/DocIterator.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/DocIterator.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/DocIterator.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/DocIterator.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,37 @@
+/**
+ * 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.search;
+
+import java.util.Iterator;
+
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public interface DocIterator extends Iterator<Integer> {
+ public boolean hasNext();
+
+ /**
+ * returns the next document id if hasNext()==true
+ */
+ public int nextDoc();
+
+ /**
+ * returns the score for the document just returned by nextDoc()
+ */
+ public float score();
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/DocIterator.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/DocList.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/DocList.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/DocList.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/DocList.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,128 @@
+/**
+ * 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.search;
+
+
+/**
+ * <code>DocList</code> represents the result of a query: an ordered list of document ids with optional score.
+ * This list contains a subset of the complete list of documents actually matched: <code>size()</code>
+ * document ids starting at <code>offset()</code>.
+ *
+ * @author yonik
+ * @version $Id: DocList.java,v 1.6 2005/11/11 21:57:56 yonik Exp $
+ * @since solr 0.9
+ */
+public interface DocList extends DocSet {
+
+ /**
+ * Returns the zero based offset of this list within the total ordered list of matches to the query.
+ */
+ public int offset();
+
+ /**
+ * Returns the number of ids in this list.
+ */
+ public int size();
+
+ /**
+ * Returns the total number of matches for the search
+ * (as opposed to just the number collected according
+ * to <code>offset()</code> and <code>size()</code>).
+ * Hence it's always true that matches() >= size()
+ * @return number of matches for the search(query&filter)
+ */
+ public int matches();
+
+
+ /***
+ public int getDoc(int pos);
+ ***/
+
+ // hmmm, what if a different slice could be generated from an existing DocSet
+ // (and was before)...
+
+ // how to distinguish cached values from logical values?
+ // docSet could represent docs 10-20, but actually contain 0-100
+ // should the big slice be cached independently, and a new class called
+ // DocListSubset be created to refer to a range within the DocList?
+
+ /**
+ * Get a subset of an existing DocList.
+ * Returns null if not possible.
+ */
+ public DocList subset(int offset, int len);
+
+ /** True if scores were retained */
+ public boolean hasScores();
+
+ /** The maximum score for the search... only valid if
+ * scores were retained (if hasScores()==true)
+ */
+ public float maxScore();
+}
+
+
+/**** Maybe do this at a higher level (more efficient)
+
+class SmartDocSet implements DocSet {
+ static int INITIAL_SIZE=10;
+ static int TRANSITION_SIZE=10;
+
+ protected BitSet bits;
+ int size;
+
+ protected int[] arr; // keep small set as an array, or as a hash?
+ protected int arrsize;
+
+ public SmartDocSet() {
+ if (INITIAL_SIZE>0) {
+ arr=new int[INITIAL_SIZE];
+ } else {
+ bits=new BitSet();
+ }
+ }
+
+
+ public void addUnique(int doc) {
+ size++;
+ if (bits != null) {
+ bits.set(doc);
+ }
+ else {
+ if (arrsize<10) {
+ arr[arrsize++]=doc;
+ } else {
+ // TODO: transition to bit set
+ }
+ }
+ };
+
+ public int size() {
+ return size;
+ }
+ public boolean exists(int docid) {
+ return false;
+ }
+ public DocSet intersection(DocSet other) {
+ return null;
+
+ }
+ public DocSet union(DocSet other) {
+ return null;
+ }
+}
+***/
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/DocList.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/DocListAndSet.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/DocListAndSet.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/DocListAndSet.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/DocListAndSet.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,37 @@
+/**
+ * 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.search;
+
+
+/**
+ * A struct who's only purpose is to hold both a DocList and a DocSet so that both
+ * may be returned from a single method.
+ * <p>
+ * The DocList and DocSet returned should <b>not</b> be modified as they may
+ * have been retrieved or inserted into a cache and should be considered shared.
+ * <p>
+ * Oh, if only java had "out" parameters or multiple return args...
+ * <p>
+ *
+ * @author yonik
+ * @version $Id: DocListAndSet.java,v 1.3 2005/04/08 05:38:05 yonik Exp $
+ * @since solr 0.9
+ */
+public final class DocListAndSet {
+ public DocList docList;
+ public DocSet docSet;
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/DocListAndSet.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/DocSet.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/DocSet.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/DocSet.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/DocSet.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,182 @@
+/**
+ * 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.search;
+
+import org.apache.solr.core.SolrException;
+
+import java.util.BitSet;
+
+/**
+ * <code>DocSet</code> represents an unordered set of Lucene Document Ids.
+ * <p>
+ * WARNING: Any DocSet returned from SolrIndexSearcher should <b>not</b> be modified as it may have been retrieved from
+ * a cache and could be shared.
+ * @author yonik
+ * @version $Id: DocSet.java,v 1.6 2005/05/13 21:20:15 yonik Exp $
+ * @since solr 0.9
+ */
+public interface DocSet /* extends Collection<Integer> */ {
+ public void add(int doc);
+ public void addUnique(int doc);
+
+ /**
+ * @return The number of document ids in the set.
+ */
+ public int size();
+
+ /**
+ *
+ * @param docid
+ * @return
+ * true if the docid is in the set
+ */
+ public boolean exists(int docid);
+
+ /**
+ *
+ * @return an interator that may be used to iterate over all of the documents in the set.
+ */
+ public DocIterator iterator();
+
+ /**
+ * Returns a BitSet view of the DocSet. Any changes to this BitSet <b>may</b>
+ * be reflected in the DocSet, hence if the DocSet is shared or was returned from
+ * a SolrIndexSearcher method, it's not safe to modify the BitSet.
+ *
+ * @return
+ * A BitSet with the bit number of every docid set in the set.
+ */
+ @Deprecated
+ public BitSet getBits();
+
+ /**
+ * Returns the approximate amount of memory taken by this DocSet.
+ * This is only an approximation and doesn't take into account java object overhead.
+ *
+ * @return
+ * the approximate memory consumption in bytes
+ */
+ public long memSize();
+
+ /**
+ * Returns the intersection of this set with another set. Neither set is modified - a new DocSet is
+ * created and returned.
+ * @param other
+ * @return a DocSet representing the intersection
+ */
+ public DocSet intersection(DocSet other);
+
+ /**
+ * Returns the number of documents of the intersection of this set with another set.
+ * May be more efficient than actually creating the intersection and then getting it's size.
+ */
+ public int intersectionSize(DocSet other);
+
+ /**
+ * Returns the union of this set with another set. Neither set is modified - a new DocSet is
+ * created and returned.
+ * @param other
+ * @return a DocSet representing the union
+ */
+ public DocSet union(DocSet other);
+
+ /**
+ * Returns the number of documents of the union of this set with another set.
+ * May be more efficient than actually creating the union and then getting it's size.
+ */
+ public int unionSize(DocSet other);
+
+}
+
+
+abstract class DocSetBase implements DocSet {
+
+ // Not implemented efficiently... for testing purposes only
+ public boolean equals(Object obj) {
+ if (!(obj instanceof DocSet)) return false;
+ DocSet other = (DocSet)obj;
+ if (this.size() != other.size()) return false;
+
+ if (this instanceof DocList && other instanceof DocList) {
+ // compare ordering
+ DocIterator i1=this.iterator();
+ DocIterator i2=this.iterator();
+ while(i1.hasNext() && i2.hasNext()) {
+ if (i1.nextDoc() != i2.nextDoc()) return false;
+ }
+ return true;
+ // don't compare matches
+ }
+
+ // if (this.size() != other.size()) return false;
+ return this.getBits().equals(other.getBits());
+ }
+
+ public void add(int doc) {
+ throw new SolrException(500,"Unsupported Operation");
+ }
+
+ public void addUnique(int doc) {
+ throw new SolrException(500,"Unsupported Operation");
+ }
+
+ // Only the inefficient base implementation. DocSets based on
+ // BitSets will return the actual BitSet without making a copy.
+ public BitSet getBits() {
+ BitSet bits = new BitSet();
+ for (DocIterator iter = iterator(); iter.hasNext();) {
+ bits.set(iter.nextDoc());
+ }
+ return bits;
+ };
+
+ public DocSet intersection(DocSet other) {
+ // intersection is overloaded in HashDocSet to be more
+ // efficient, so if "other" is a HashDocSet, dispatch off
+ // of it instead.
+ if (other instanceof HashDocSet) {
+ return other.intersection(this);
+ }
+
+ // Default... handle with bitsets.
+ BitSet newbits = (BitSet)(this.getBits().clone());
+ newbits.and(other.getBits());
+ return new BitDocSet(newbits);
+ }
+
+ public DocSet union(DocSet other) {
+ BitSet newbits = (BitSet)(this.getBits().clone());
+ newbits.or(other.getBits());
+ return new BitDocSet(newbits);
+ }
+
+ // TODO: more efficient implementations
+ public int intersectionSize(DocSet other) {
+ return intersection(other).size();
+ }
+
+ // TODO: more efficient implementations
+ public int unionSize(DocSet other) {
+ return union(other).size();
+ }
+
+
+}
+
+
+
+
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/DocSet.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/DocSlice.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/DocSlice.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/DocSlice.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/DocSlice.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,119 @@
+/**
+ * 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.search;
+
+/**
+ * <code>DocSlice</code> implements DocList as an array of docids and optional scores.
+ *
+ * @author yonik
+ * @version $Id: DocSlice.java,v 1.9 2005/11/11 21:57:56 yonik Exp $
+ * @since solr 0.9
+ */
+public class DocSlice extends DocSetBase implements DocList {
+ final int offset; // starting position of the docs (zero based)
+ final int len; // number of positions used in arrays
+ final int[] docs; // a slice of documents (docs 0-100 of the query)
+
+ final float[] scores; // optional score list
+ final int matches;
+ final float maxScore;
+
+ /**
+ *
+ * @param offset starting offset for this range of docs
+ * @param len length of results
+ * @param docs array of docids starting at position 0
+ * @param scores
+ * @param matches total number of matches for the query
+ */
+ public DocSlice(int offset, int len, int[] docs, float[] scores, int matches, float maxScore) {
+ this.offset=offset;
+ this.len=len;
+ this.docs=docs;
+ this.scores=scores;
+ this.matches=matches;
+ this.maxScore=maxScore;
+ }
+
+ public DocList subset(int offset, int len) {
+ if (this.offset == offset && this.len==len) return this;
+
+ // if we didn't store enough (and there was more to store)
+ // then we can't take a subset.
+ int requestedEnd = offset + len;
+ if (requestedEnd > docs.length && this.matches > docs.length) return null;
+ int realEndDoc = Math.min(requestedEnd, docs.length);
+ int realLen = Math.max(realEndDoc-offset,0);
+ if (this.offset == offset && this.len == realLen) return this;
+ return new DocSlice(offset, realLen, docs, scores, matches, maxScore);
+ }
+
+ public boolean hasScores() {
+ return scores!=null;
+ }
+
+ public float maxScore() {
+ return maxScore;
+ }
+
+
+ public int offset() { return offset; }
+ public int size() { return len; }
+ public int matches() { return matches; }
+
+
+ public long memSize() {
+ return (docs.length<<2)
+ + (scores==null ? 0 : (scores.length<<2))
+ + 24;
+ }
+
+
+ public boolean exists(int doc) {
+ for (int i: docs) {
+ if (i==doc) return true;
+ }
+ return false;
+ }
+
+ // Hmmm, maybe I could have reused the scorer interface here...
+ // except that it carries Similarity baggage...
+ public DocIterator iterator() {
+ return new DocIterator() {
+ int pos=offset;
+ final int end=offset+len;
+ public boolean hasNext() {
+ return pos < end;
+ }
+
+ public Integer next() {
+ return nextDoc();
+ }
+
+ public void remove() {
+ }
+
+ public int nextDoc() {
+ return docs[pos++];
+ }
+
+ public float score() {
+ return scores[pos-1];
+ }
+ };
+ }
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/DocSlice.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/HashDocSet.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/HashDocSet.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/HashDocSet.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/HashDocSet.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,280 @@
+/**
+ * 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.search;
+
+import org.apache.solr.core.SolrConfig;
+
+
+/**
+ * <code>HashDocSet</code> represents an unordered set of Lucene Document Ids
+ * using a primitive int hash table. It can be a better choice if there are few docs
+ * in the set because it takes up less memory and is faster to iterate and take
+ * set intersections.
+ *
+ * @author yonik
+ * @version $Id: HashDocSet.java,v 1.7 2005/11/22 17:16:19 yonik Exp $
+ * @since solr 0.9
+ */
+public final class HashDocSet extends DocSetBase {
+ // keep track of the inverse of the Loadfactor since
+ // multiplication is so much faster than division.
+ final static float inverseLoadfactor = 1.0f / SolrConfig.config.getFloat("//HashDocSet/@loadFactor",0.75f);
+ public final static int MAX_SIZE = SolrConfig.config.getInt("//HashDocSet/@maxSize",-1);
+
+
+ // lucene docs are numbered from 0, so a neg number must be used for missing.
+ // an alternative to having to init the array to EMPTY at the start is
+ //
+ private final static int EMPTY=-1;
+ private final int tablesize;
+ private final int[] table;
+ private final int size;
+
+ private final int mask;
+
+ public HashDocSet(int[] docs, int offset, int len) {
+ int tsize = Math.max(nextHighestPowerOfTwo(len), 1);
+ if (tsize < len * inverseLoadfactor) {
+ tsize <<= 1;
+ }
+ tablesize = tsize;
+ mask=tablesize-1;
+
+ table = new int[tablesize];
+ for (int i=0; i<tablesize; i++) table[i]=EMPTY;
+
+ for (int i=offset; i<len; i++) {
+ put(docs[i]);
+ }
+
+ size = len;
+ }
+
+ static int nextHighestPowerOfTwo(int v) {
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v++;
+ return v;
+ }
+
+
+ void put(int doc) {
+ table[getSlot(doc)]=doc;
+ }
+
+ private int getSlot(int val) {
+ int s,v;
+ s=val & mask;
+ v=table[s];
+ // check for EMPTY first since that value is more likely
+ if (v==EMPTY || v==val) return s;
+ s=rehash(val);
+ return s;
+ }
+
+
+ // As the size of this int hashtable is expected to be small
+ // (thousands at most), I did not try to keep the rehash function
+ // reversible (important to avoid collisions in large hash tables).
+ private int rehash(int val) {
+ int h,s,v;
+ final int comp=~val;
+
+ // don't left shift too far... the only bits
+ // that count in the answer are the ones on the right.
+ // We want to put more of the bits on the left
+ // into the answer.
+ // Keep small tables in mind. We may be only using
+ // the first 5 or 6 bits.
+
+ // on the first rehash, use complement instead of val to shift
+ // so we don't end up with 0 again if val==0.
+ h = val ^ (comp>>8);
+ s = h & mask;
+ v = table[s];
+ if (v==EMPTY || v==val) return s;
+
+ h ^= (v << 17) | (comp >>> 16); // this is reversible
+ s = h & mask;
+ v = table[s];
+ if (v==EMPTY || v==val) return s;
+
+ h ^= (h << 8) | (comp >>> 25); // this is reversible
+ s = h & mask;
+ v = table[s];
+ if (v==EMPTY || v==val) return s;
+
+ /**********************
+ // Knuth, Thomas Wang, http://www.concentric.net/~Ttwang/tech/inthash.htm
+ // This magic number has no common factors with 2^32, and magic/(2^32) approximates
+ // the golden ratio.
+ private static final int magic = (int)2654435761L;
+
+ h = magic*val;
+ s = h & mask;
+ v=table[s];
+ if (v==EMPTY || v==val) return s;
+
+ // the mult with magic should have thoroughly mixed the bits.
+ // add entropy to the right half from the left half.
+ h ^= h>>>16;
+ s = h & mask;
+ v=table[s];
+ if (v==EMPTY || v==val) return s;
+ *************************/
+
+ // linear scan now... ug.
+ final int start=s;
+ while (++s<tablesize) {
+ v=table[s];
+ if (v==EMPTY || v==val) return s;
+ }
+ s=start;
+ while (--s>=0) {
+ v=table[s];
+ if (v==EMPTY || v==val) return s;
+ }
+ return s;
+ }
+
+
+ /**
+ *
+ * @return The number of document ids in the set.
+ */
+ public int size() {
+ return size;
+ }
+
+ public boolean exists(int docid) {
+ int v = table[docid & mask];
+ if (v==EMPTY) return false;
+ else if (v==docid) return true;
+ else {
+ v = table[rehash(docid)];
+ if (v==docid) return true;
+ else return false;
+ }
+ }
+
+ public DocIterator iterator() {
+ return new DocIterator() {
+ int pos=0;
+ int doc;
+ { goNext(); }
+
+ public boolean hasNext() {
+ return pos < tablesize;
+ }
+
+ public Integer next() {
+ return nextDoc();
+ }
+
+ public void remove() {
+ }
+
+ void goNext() {
+ while (pos<tablesize && table[pos]==EMPTY) pos++;
+ }
+
+ // modify to return -1 at end of iteration?
+ public int nextDoc() {
+ int doc = table[pos];
+ pos++;
+ goNext();
+ return doc;
+ }
+
+ public float score() {
+ return 0.0f;
+ }
+ };
+ }
+
+
+ public long memSize() {
+ return (tablesize<<2) + 20;
+ }
+
+
+ public DocSet intersection(DocSet other) {
+ if (other instanceof HashDocSet) {
+ // set "a" to the smallest doc set for the most efficient
+ // intersection.
+ final HashDocSet a = size()<=other.size() ? this : (HashDocSet)other;
+ final HashDocSet b = size()<=other.size() ? (HashDocSet)other : this;
+
+ int[] result = new int[a.size()];
+ int resultCount=0;
+ for (int i=0; i<a.table.length; i++) {
+ int id=a.table[i];
+ if (id >= 0 && b.exists(id)) {
+ result[resultCount++]=id;
+ }
+ }
+ return new HashDocSet(result,0,resultCount);
+
+ } else {
+
+ int[] result = new int[size()];
+ int resultCount=0;
+ for (int i=0; i<table.length; i++) {
+ int id=table[i];
+ if (id >= 0 && other.exists(id)) {
+ result[resultCount++]=id;
+ }
+ }
+ return new HashDocSet(result,0,resultCount);
+ }
+
+ }
+
+ public int intersectionSize(DocSet other) {
+ if (other instanceof HashDocSet) {
+ // set "a" to the smallest doc set for the most efficient
+ // intersection.
+ final HashDocSet a = size()<=other.size() ? this : (HashDocSet)other;
+ final HashDocSet b = size()<=other.size() ? (HashDocSet)other : this;
+
+ int resultCount=0;
+ for (int i=0; i<a.table.length; i++) {
+ int id=a.table[i];
+ if (id >= 0 && b.exists(id)) {
+ resultCount++;
+ }
+ }
+ return resultCount;
+ } else {
+ int resultCount=0;
+ for (int i=0; i<table.length; i++) {
+ int id=table[i];
+ if (id >= 0 && other.exists(id)) {
+ resultCount++;
+ }
+ }
+ return resultCount;
+ }
+
+ }
+
+
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/HashDocSet.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/LRUCache.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/LRUCache.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/LRUCache.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/LRUCache.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,274 @@
+/**
+ * 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.search;
+
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.core.SolrException;
+import org.apache.solr.util.NamedList;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
+import java.io.IOException;
+import java.net.URL;
+
+
+/**
+ * @author yonik
+ * @version $Id: LRUCache.java,v 1.12 2005/11/30 06:12:55 yonik Exp $
+ */
+public class LRUCache implements SolrCache {
+
+ /* An instance of this class will be shared across multiple instances
+ * of an LRUCache at the same time. Make sure everything is thread safe.
+ */
+ private static class CumulativeStats {
+ AtomicLong lookups = new AtomicLong();
+ AtomicLong hits = new AtomicLong();
+ AtomicLong inserts = new AtomicLong();
+ AtomicLong evictions = new AtomicLong();
+ }
+
+ private CumulativeStats stats;
+
+ // per instance stats. The synchronization used for the map will also be
+ // used for updating these statistics (and hence they are not AtomicLongs
+ private long lookups;
+ private long hits;
+ private long inserts;
+ private long evictions;
+
+ private Map map;
+ private String name;
+ private int autowarmCount;
+ private State state;
+ private CacheRegenerator regenerator;
+
+ public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
+ state=State.CREATED;
+ this.regenerator = regenerator;
+ name = (String)args.get("name");
+ String str = (String)args.get("size");
+ final int limit = str==null ? 1024 : Integer.parseInt(str);
+ str = (String)args.get("initialSize");
+ final int initialSize = Math.min(str==null ? 1024 : Integer.parseInt(str), limit);
+ str = (String)args.get("autowarmCount");
+ autowarmCount = str==null ? 0 : Integer.parseInt(str);
+
+ map = new LinkedHashMap(initialSize, 0.75f, true) {
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ if (size() > limit) {
+ // increment evictions regardless of state.
+ // this doesn't need to be synchronized because it will
+ // only be called in the context of a higher level synchronized block.
+ evictions++;
+ stats.evictions.incrementAndGet();
+ return true;
+ }
+ return false;
+ }
+ };
+
+ if (persistence==null) {
+ // must be the first time a cache of this type is being created
+ persistence = new CumulativeStats();
+ }
+
+ stats = (CumulativeStats)persistence;
+
+ return persistence;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public int size() {
+ synchronized(map) {
+ return map.size();
+ }
+ }
+
+ public synchronized Object put(Object key, Object value) {
+ if (state == State.LIVE) {
+ stats.inserts.incrementAndGet();
+ }
+
+ synchronized (map) {
+ // increment local inserts regardless of state???
+ // it does make it more consistent with the current size...
+ inserts++;
+ return map.put(key,value);
+ }
+ }
+
+ public Object get(Object key) {
+ synchronized (map) {
+ Object val = map.get(key);
+ if (state == State.LIVE) {
+ // only increment lookups and hits if we are live.
+ lookups++;
+ stats.lookups.incrementAndGet();
+ if (val!=null) {
+ hits++;
+ stats.hits.incrementAndGet();
+ }
+ }
+ return val;
+ }
+ }
+
+ public void clear() {
+ synchronized(map) {
+ map.clear();
+ }
+ }
+
+ public void setState(State state) {
+ this.state = state;
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public void warm(SolrIndexSearcher searcher, SolrCache old) throws IOException {
+ if (regenerator==null) return;
+
+ LRUCache other = (LRUCache)old;
+
+ // warm entries
+ if (autowarmCount != 0) {
+ Object[] keys,vals = null;
+
+ // Don't do the autowarming in the synchronized block, just pull out the keys and values.
+ synchronized (other.map) {
+ int sz = other.map.size();
+ if (autowarmCount!=-1) sz = Math.min(sz,autowarmCount);
+ keys = new Object[sz];
+ vals = new Object[sz];
+
+ Iterator iter = other.map.entrySet().iterator();
+
+ // iteration goes from oldest (least recently used) to most recently used,
+ // so we need to skip over the oldest entries.
+ int skip = other.map.size() - sz;
+ for (int i=0; i<skip; i++) iter.next();
+
+
+ for (int i=0; i<sz; i++) {
+ Map.Entry entry = (Map.Entry)iter.next();
+ keys[i]=entry.getKey();
+ vals[i]=entry.getValue();
+ }
+ }
+
+ // autowarm from the oldest to the newest entries so that the ordering will be
+ // correct in the new cache.
+ for (int i=0; i<keys.length; i++) {
+ try {
+ boolean continueRegen = regenerator.regenerateItem(searcher, this, old, keys[i], vals[i]);
+ if (!continueRegen) break;
+ }
+ catch (Throwable e) {
+ SolrException.log(log,"Error during auto-warming of key:" + keys[i], e);
+ }
+ }
+ }
+ }
+
+
+ public void close() {
+ }
+
+
+ //////////////////////// SolrInfoMBeans methods //////////////////////
+
+
+ public String getName() {
+ return LRUCache.class.getName();
+ }
+
+ public String getVersion() {
+ return SolrCore.version;
+ }
+
+ public String getDescription() {
+ return "LRU Cache";
+ }
+
+ public Category getCategory() {
+ return Category.CACHE;
+ }
+
+ public String getCvsId() {
+ return "$Id: LRUCache.java,v 1.12 2005/11/30 06:12:55 yonik Exp $";
+ }
+
+ public String getCvsName() {
+ return "$Name: $";
+ }
+
+ public String getCvsSource() {
+ return "$Source: /cvs/main/searching/solr/solarcore/src/solr/search/LRUCache.java,v $";
+ }
+
+ public URL[] getDocs() {
+ return null;
+ }
+
+
+ // returns a ratio, not a percent.
+ private static String calcHitRatio(long lookups, long hits) {
+ if (lookups==0) return "0.00";
+ if (lookups==hits) return "1.00";
+ int hundredths = (int)(hits*100/lookups); // rounded down
+ if (hundredths < 10) return "0.0" + hundredths;
+ return "0." + hundredths;
+
+ /*** code to produce a percent, if we want it...
+ int ones = (int)(hits*100 / lookups);
+ int tenths = (int)(hits*1000 / lookups) - ones*10;
+ return Integer.toString(ones) + '.' + tenths;
+ ***/
+ }
+
+ public NamedList getStatistics() {
+ NamedList lst = new NamedList();
+ synchronized (map) {
+ lst.add("lookups", lookups);
+ lst.add("hits", hits);
+ lst.add("hitratio", calcHitRatio(lookups,hits));
+ lst.add("inserts", inserts);
+ lst.add("evictions", evictions);
+ lst.add("size", map.size());
+ }
+
+ long clookups = stats.lookups.get();
+ long chits = stats.hits.get();
+ lst.add("cumulative_lookups", clookups);
+ lst.add("cumulative_hits", chits);
+ lst.add("cumulative_hitratio", calcHitRatio(clookups,chits));
+ lst.add("cumulative_inserts", stats.inserts.get());
+ lst.add("cumulative_evictions", stats.evictions.get());
+
+ return lst;
+ }
+
+ public String toString() {
+ return name + getStatistics().toString();
+ }
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/LRUCache.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/LuceneQueryOptimizer.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/LuceneQueryOptimizer.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/LuceneQueryOptimizer.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/LuceneQueryOptimizer.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,116 @@
+/**
+ * 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.search;
+
+/* Copyright (c) 2003 The Nutch Organization. All rights reserved. */
+/* Use subject to the conditions in http://www.nutch.org/LICENSE.txt. */
+
+
+import org.apache.lucene.search.*;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.io.IOException;
+
+/** Utility which converts certain query clauses into {@link QueryFilter}s and
+ * caches these. Only required {@link TermQuery}s whose boost is zero and
+ * whose term occurs in at least a certain fraction of documents are converted
+ * to cached filters. This accellerates query constraints like language,
+ * document format, etc., which do not affect ranking but might otherwise slow
+ * search considerably. */
+// Taken from Nutch and modified - YCS
+class LuceneQueryOptimizer {
+ private LinkedHashMap cache; // an LRU cache of QueryFilter
+
+ private float threshold;
+
+ /** Construct an optimizer that caches and uses filters for required {@link
+ * TermQuery}s whose boost is zero.
+ * @param cacheSize the number of QueryFilters to cache
+ * @param threshold the fraction of documents which must contain term
+ */
+ public LuceneQueryOptimizer(final int cacheSize, float threshold) {
+ this.cache = new LinkedHashMap(cacheSize, 0.75f, true) {
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() > cacheSize; // limit size of cache
+ }
+ };
+ this.threshold = threshold;
+ }
+
+ public TopDocs optimize(BooleanQuery original,
+ Searcher searcher,
+ int numHits,
+ Query[] queryOut,
+ Filter[] filterOut
+ )
+ throws IOException {
+
+ BooleanQuery query = new BooleanQuery();
+ BooleanQuery filterQuery = null;
+
+ BooleanClause[] clauses = original.getClauses();
+ for (int i = 0; i < clauses.length; i++) {
+ BooleanClause c = clauses[i];
+
+/***
+System.out.println("required="+c.required);
+System.out.println("boost="+c.query.getBoost());
+System.out.println("isTermQuery="+(c.query instanceof TermQuery));
+if (c.query instanceof TermQuery) {
+ System.out.println("term="+((TermQuery)c.query).getTerm());
+ System.out.println("docFreq="+searcher.docFreq(((TermQuery)c.query).getTerm()));
+}
+***/
+ if (c.required // required
+ && c.query.getBoost() == 0.0f // boost is zero
+ && c.query instanceof TermQuery // TermQuery
+ && (searcher.docFreq(((TermQuery)c.query).getTerm())
+ / (float)searcher.maxDoc()) >= threshold) { // check threshold
+ if (filterQuery == null)
+ filterQuery = new BooleanQuery();
+ filterQuery.add(c.query, true, false); // filter it
+//System.out.println("WooHoo... qualified to be hoisted to a filter!");
+ } else {
+ query.add(c); // query it
+ }
+ }
+
+ Filter filter = null;
+ if (filterQuery != null) {
+ synchronized (cache) { // check cache
+ filter = (Filter)cache.get(filterQuery);
+ }
+ if (filter == null) { // miss
+ filter = new QueryFilter(filterQuery); // construct new entry
+ synchronized (cache) {
+ cache.put(filterQuery, filter); // cache it
+ }
+ }
+ }
+
+ // YCS: added code to pass out optimized query and filter
+ // so they can be used with Hits
+ if (queryOut != null && filterOut != null) {
+ queryOut[0] = query; filterOut[0] = filter;
+ return null;
+ } else {
+ return searcher.search(query, filter, numHits);
+ }
+
+ }
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/LuceneQueryOptimizer.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/MissingStringLastComparatorSource.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/MissingStringLastComparatorSource.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/MissingStringLastComparatorSource.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/MissingStringLastComparatorSource.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,115 @@
+/**
+ * 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.search;
+
+import org.apache.lucene.search.*;
+import org.apache.lucene.index.IndexReader;
+
+import java.io.IOException;
+
+
+/**
+ * A {@link SortComparatorSource} for strings that orders null values after non-null values.
+ * Based on FieldSortedHitQueue.comparatorString
+ * <p>
+ *
+ * @author Chris Hostetter
+ * @author yonik
+ * @version $Id: MissingStringLastComparatorSource.java,v 1.1 2005/06/02 04:43:06 yonik Exp $
+ *
+ */
+
+// move to apache package and make public if it is accepted as a patch
+class MissingStringLastComparatorSource implements SortComparatorSource {
+
+ public static final String bigString="\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffffNULL_VAL";
+
+ private final String missingValueProxy;
+
+ public MissingStringLastComparatorSource() {
+ this(bigString);
+ }
+
+ /**
+ * Returns the value used to sort the given document. The
+ * object returned must implement the java.io.Serializable
+ * interface. This is used by multisearchers to determine how to collate results from their searchers.
+ * @see FieldDoc
+ * @param i Document
+ * @return Serializable object
+ */
+
+ /** Creates a {@link SortComparatorSource} that uses <tt>missingValueProxy</tt> as the value to return from ScoreDocComparator.sortValue()
+ * which is only used my multisearchers to determine how to collate results from their searchers.
+ *
+ * @param missingValueProxy The value returned when sortValue() is called for a document missing the sort field.
+ * This value is *not* normally used for sorting, but used to create
+ */
+ public MissingStringLastComparatorSource(String missingValueProxy) {
+ this.missingValueProxy=missingValueProxy;
+ }
+
+ public ScoreDocComparator newComparator(final IndexReader reader,
+ final String fieldname)
+ throws IOException {
+
+ final String field = fieldname.intern();
+ final FieldCache.StringIndex index =
+ FieldCache.DEFAULT.getStringIndex (reader, field);
+
+ // :HACK:
+ // final String lastString =
+ // (index.lookup[index.lookup.length-1]+"X").intern();
+ //
+ // Note: basing lastStringValue on the StringIndex won't work
+ // with a multisearcher.
+
+
+ return new ScoreDocComparator () {
+
+ public final int compare (final ScoreDoc i, final ScoreDoc j) {
+ final int fi = index.order[i.doc];
+ final int fj = index.order[j.doc];
+
+ // 0 is the magic position of null
+
+ /**** alternate logic
+ if (fi < fj && fi != 0) return -1;
+ if (fj < fi && fj != 0) return 1;
+ if (fi==fj) return 0;
+ return fi==0 ? 1 : -1;
+ ****/
+
+ if (fi==fj) return 0;
+ if (fi==0) return 1;
+ if (fj==0) return -1;
+ return fi < fj ? -1 : 1;
+
+ }
+
+ public Comparable sortValue (final ScoreDoc i) {
+ int f = index.order[i.doc];
+ return (0 == f) ? missingValueProxy : index.lookup[f];
+ }
+
+ public int sortType() {
+ return SortField.CUSTOM;
+ }
+ };
+
+ }
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/MissingStringLastComparatorSource.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/solr/trunk/src/java/org/apache/solr/search/QueryParsing.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/search/QueryParsing.java?rev=372455&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/search/QueryParsing.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/search/QueryParsing.java Wed Jan 25 21:37:29 2006
@@ -0,0 +1,479 @@
+/**
+ * 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.search;
+
+import org.apache.lucene.search.*;
+import org.apache.lucene.search.function.*;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.Term;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.core.SolrException;
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.schema.SchemaField;
+import org.apache.solr.schema.FieldType;
+
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+import java.util.logging.Level;
+import java.io.IOException;
+
+/**
+ * @author yonik
+ * @version $Id: QueryParsing.java,v 1.10 2005/12/20 21:34:44 yonik Exp $
+ */
+public class QueryParsing {
+
+ public static Query parseQuery(String qs, IndexSchema schema) {
+ try {
+ Query query = new SolrQueryParser(schema).parse(qs);
+
+ if (SolrCore.log.isLoggable(Level.FINEST)) {
+ SolrCore.log.finest("After QueryParser:" + query);
+ }
+
+ return query;
+
+ } catch (ParseException e) {
+ SolrCore.log(e);
+ throw new SolrException(400,"Error parsing Lucene query",e);
+ }
+ }
+
+
+
+ /***
+ * SortSpec encapsulates a Lucene Sort and a count of the number of documents
+ * to return.
+ */
+ public static class SortSpec {
+ private final Sort sort;
+ private final int num;
+
+ SortSpec(Sort sort, int num) {
+ this.sort=sort;
+ this.num=num;
+ }
+
+ /**
+ * Gets the Lucene Sort object, or null for the default sort
+ * by score descending.
+ */
+ public Sort getSort() { return sort; }
+
+ /**
+ * Gets the number of documens to return after sorting.
+ * -1 means there is no cutoff (only do the sort)
+ * @return
+ */
+ public int getCount() { return num; }
+ }
+
+
+ private static Pattern sortSeparator = Pattern.compile("[\\s,]+");
+
+ /**
+ * Returns null if the sortSpec string doesn't look like a sort specification,
+ * or if the sort specification couldn't be converted into a Lucene Sort
+ * (because of a field not being indexed or undefined, etc).
+ *
+ * The form of the sort specification string currently parsed is:
+ * SortSpec ::= SingleSort [, SingleSort]* <number>?
+ * SingleSort ::= <fieldname> SortDirection
+ * SortDirection ::= top | desc | bottom | asc
+ *
+ * Examples:
+ * top 10 #take the top 10 by score
+ * desc 10 #take the top 10 by score
+ * score desc 10 #take the top 10 by score
+ * weight bottom 10 #sort by weight ascending and take the first 10
+ * weight desc #sort by weight descending
+ * height desc,weight desc #sort by height descending, and use weight descending to break any ties
+ * height desc,weight asc top 20 #sort by height descending, using weight ascending as a tiebreaker
+ *
+ */
+ public static SortSpec parseSort(String sortSpec, IndexSchema schema) {
+ if (sortSpec==null || sortSpec.length()==0) return null;
+
+ // I wonder how fast the regex is??? as least we cache the pattern.
+ String[] parts = sortSeparator.split(sortSpec.trim(),0);
+ if (parts.length == 0) return null;
+
+ ArrayList<SortField> lst = new ArrayList<SortField>();
+ int num=-1;
+
+ int pos=0;
+ String fn;
+ boolean top=true;
+ boolean normalSortOnScore=false;
+
+ while (pos < parts.length) {
+ String str=parts[pos];
+ if ("top".equals(str) || "bottom".equals(str) || "asc".equals(str) || "desc".equals(str)) {
+ // if the field name seems to be missing, default to "score".
+ // note that this will mess up a field name that has the same name
+ // as a sort direction specifier.
+ fn="score";
+ } else {
+ fn=str;
+ pos++;
+ }
+
+ // get the direction of the sort
+ str=parts[pos];
+ if ("top".equals(str) || "desc".equals(str)) {
+ top=true;
+ } else if ("bottom".equals(str) || "asc".equals(str)) {
+ top=false;
+ } else {
+ return null; // must not be a sort command
+ }
+
+ // get the field to sort on
+ // hmmm - should there be a fake/pseudo-field named "score" in the schema?
+ if ("score".equals(fn)) {
+ if (top) {
+ normalSortOnScore=true;
+ lst.add(SortField.FIELD_SCORE);
+ } else {
+ lst.add(new SortField(null, SortField.SCORE, true));
+ }
+ } else {
+ // getField could throw an exception if the name isn't found
+ try {
+ SchemaField f = schema.getField(fn);
+ if (f == null || !f.indexed()) return null;
+ lst.add(f.getType().getSortField(f,top));
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ pos++;
+
+ // If there is a leftover part, assume it is a count
+ if (pos+1 == parts.length) {
+ try {
+ num = Integer.parseInt(parts[pos]);
+ } catch (Exception e) {
+ return null;
+ }
+ pos++;
+ }
+ }
+
+ Sort sort;
+ if (normalSortOnScore && lst.size() == 1) {
+ // Normalize the default sort on score descending to sort=null
+ sort=null;
+ } else {
+ sort = new Sort((SortField[]) lst.toArray(new SortField[lst.size()]));
+ }
+ return new SortSpec(sort,num);
+ }
+
+
+ ///////////////////////////
+ ///////////////////////////
+ ///////////////////////////
+
+ static FieldType writeFieldName(String name, IndexSchema schema, Appendable out, int flags) throws IOException {
+ FieldType ft = null;
+ ft = schema.getFieldTypeNoEx(name);
+ out.append(name);
+ if (ft==null) {
+ out.append("(UNKNOWN FIELD "+name+')');
+ }
+ out.append(':');
+ return ft;
+ }
+
+ static void writeFieldVal(String val, FieldType ft, Appendable out, int flags) throws IOException {
+ if (ft!=null) {
+ out.append(ft.toExternal(new Field("",val,true,true,false)));
+ } else {
+ out.append(val);
+ }
+ }
+
+ public static void toString(Query query, IndexSchema schema, Appendable out, int flags) throws IOException {
+ boolean writeBoost=true;
+
+ if (query instanceof TermQuery) {
+ TermQuery q = (TermQuery)query;
+ Term t = q.getTerm();
+ FieldType ft = writeFieldName(t.field(), schema, out, flags);
+ writeFieldVal(t.text(), ft, out, flags);
+ } else if (query instanceof RangeQuery) {
+ RangeQuery q = (RangeQuery)query;
+ String fname = q.getField();
+ FieldType ft = writeFieldName(fname, schema, out, flags);
+ out.append( q.isInclusive() ? '[' : '{' );
+ Term lt = q.getLowerTerm();
+ Term ut = q.getUpperTerm();
+ if (lt==null) {
+ out.append('*');
+ } else {
+ writeFieldVal(lt.text(), ft, out, flags);
+ }
+
+ out.append(" TO ");
+
+ if (ut==null) {
+ out.append('*');
+ } else {
+ writeFieldVal(ut.text(), ft, out, flags);
+ }
+
+ out.append( q.isInclusive() ? ']' : '}' );
+
+ } else if (query instanceof ConstantScoreRangeQuery) {
+ ConstantScoreRangeQuery q = (ConstantScoreRangeQuery)query;
+ String fname = q.getField();
+ FieldType ft = writeFieldName(fname, schema, out, flags);
+ out.append( q.includesLower() ? '[' : '{' );
+ String lt = q.getLowerVal();
+ String ut = q.getUpperVal();
+ if (lt==null) {
+ out.append('*');
+ } else {
+ writeFieldVal(lt, ft, out, flags);
+ }
+
+ out.append(" TO ");
+
+ if (ut==null) {
+ out.append('*');
+ } else {
+ writeFieldVal(ut, ft, out, flags);
+ }
+
+ out.append( q.includesUpper() ? ']' : '}' );
+ } else if (query instanceof BooleanQuery) {
+ BooleanQuery q = (BooleanQuery)query;
+ boolean needParens=false;
+
+ if (q.getBoost() != 1.0 || q.getMinimumNumberShouldMatch() != 0) {
+ needParens=true;
+ }
+ if (needParens) {
+ out.append('(');
+ }
+ BooleanClause[] clauses = q.getClauses();
+ boolean first=true;
+ for (BooleanClause c : clauses) {
+ if (!first) {
+ out.append(' ');
+ } else {
+ first=false;
+ }
+
+ if (c.prohibited) {
+ out.append('-');
+ } else if (c.required) {
+ out.append('+');
+ }
+ Query subQuery = c.query;
+ boolean wrapQuery=false;
+
+ // TODO: may need to put parens around other types
+ // of queries too, depending on future syntax.
+ if (subQuery instanceof BooleanQuery) {
+ wrapQuery=true;
+ }
+
+ if (wrapQuery) {
+ out.append('(');
+ }
+
+ toString(subQuery, schema, out, flags);
+
+ if (wrapQuery) {
+ out.append(')');
+ }
+ }
+
+ if (needParens) {
+ out.append(')');
+ }
+ if (q.getMinimumNumberShouldMatch()>0) {
+ out.append('~');
+ out.append(Integer.toString(q.getMinimumNumberShouldMatch()));
+ }
+
+ } else if (query instanceof PrefixQuery) {
+ PrefixQuery q = (PrefixQuery)query;
+ Term prefix = q.getPrefix();
+ FieldType ft = writeFieldName(prefix.field(), schema, out, flags);
+ out.append(prefix.text());
+ out.append('*');
+ } else if (query instanceof ConstantScorePrefixQuery) {
+ ConstantScorePrefixQuery q = (ConstantScorePrefixQuery)query;
+ Term prefix = q.getPrefix();
+ FieldType ft = writeFieldName(prefix.field(), schema, out, flags);
+ out.append(prefix.text());
+ out.append('*');
+ } else if (query instanceof WildcardQuery) {
+ out.append(query.toString());
+ writeBoost=false;
+ } else if (query instanceof FuzzyQuery) {
+ out.append(query.toString());
+ writeBoost=false;
+ } else if (query instanceof ConstantScoreQuery) {
+ out.append(query.toString());
+ writeBoost=false;
+ } else {
+ out.append(query.getClass().getSimpleName()
+ + '(' + query.toString() + ')' );
+ writeBoost=false;
+ }
+
+ if (writeBoost && query.getBoost() != 1.0f) {
+ out.append("^");
+ out.append(Float.toString(query.getBoost()));
+ }
+
+ }
+
+ public static String toString(Query query, IndexSchema schema) {
+ try {
+ StringBuilder sb = new StringBuilder();
+ toString(query, schema, sb, 0);
+ return sb.toString();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+
+
+ // simple class to help with parsing a string
+ private static class StrParser {
+ String val;
+ int pos;
+ int end;
+
+ StrParser(String val) {this.val = val; end=val.length(); }
+
+ void eatws() {
+ while (pos<end && Character.isWhitespace(val.charAt(pos))) pos++;
+ }
+
+ boolean opt(String s) {
+ eatws();
+ int slen=s.length();
+ if (val.regionMatches(pos, s, 0, slen)) {
+ pos+=slen;
+ return true;
+ }
+ return false;
+ }
+
+ void expect(String s) throws ParseException {
+ eatws();
+ int slen=s.length();
+ if (val.regionMatches(pos, s, 0, slen)) {
+ pos+=slen;
+ } else {
+ throw new ParseException("Expected '"+s+"' at position " + pos + " in '"+val+"'");
+ }
+ }
+
+ float getFloat() throws ParseException {
+ eatws();
+ char[] arr = new char[end-pos];
+ int i;
+ for (i=0; i<arr.length; i++) {
+ char ch = val.charAt(pos);
+ if ( (ch>='0' && ch<='9')
+ || ch=='+' || ch=='-'
+ || ch=='.' || ch=='e' || ch=='E'
+ ) {
+ pos++;
+ arr[i]=ch;
+ } else {
+ break;
+ }
+ }
+
+ return Float.parseFloat(new String(arr,0,i));
+ }
+
+ String getId() throws ParseException {
+ eatws();
+ int id_start=pos;
+ while (pos<end && Character.isJavaIdentifierPart(val.charAt(pos))) pos++;
+ return val.substring(id_start, pos);
+ }
+
+ char peek() {
+ eatws();
+ return pos<end ? val.charAt(pos) : 0;
+ }
+
+ public String toString() {
+ return "'" + val + "'" + ", pos=" + pos;
+ }
+
+ }
+
+
+ private static ValueSource parseValSource(StrParser sp, IndexSchema schema) throws ParseException {
+ String id = sp.getId();
+ if (sp.opt("(")) {
+ // a function: could contain a fieldname or another function.
+ ValueSource vs=null;
+ if (id.equals("ord")) {
+ String field = sp.getId();
+ vs = new OrdFieldSource(field);
+ } else if (id.equals("rord")) {
+ String field = sp.getId();
+ vs = new ReverseOrdFieldSource(field);
+ } else if (id.equals("linear")) {
+ ValueSource source = parseValSource(sp, schema);
+ sp.expect(",");
+ float slope = sp.getFloat();
+ sp.expect(",");
+ float intercept = sp.getFloat();
+ vs = new LinearFloatFunction(source,slope,intercept);
+ } else if (id.equals("recip")) {
+ ValueSource source = parseValSource(sp,schema);
+ sp.expect(",");
+ float m = sp.getFloat();
+ sp.expect(",");
+ float a = sp.getFloat();
+ sp.expect(",");
+ float b = sp.getFloat();
+ vs = new ReciprocalFloatFunction(source,m,a,b);
+ } else {
+ throw new ParseException("Unknown function " + id + " in FunctionQuery(" + sp + ")");
+ }
+ sp.expect(")");
+ return vs;
+ }
+
+ SchemaField f = schema.getField(id);
+ return f.getType().getValueSource(f);
+ }
+
+ /** Parse a function, returning a FunctionQuery
+ */
+ public static FunctionQuery parseFunction(String func, IndexSchema schema) throws ParseException {
+ return new FunctionQuery(parseValSource(new StrParser(func), schema));
+ }
+
+}
Propchange: incubator/solr/trunk/src/java/org/apache/solr/search/QueryParsing.java
------------------------------------------------------------------------------
svn:eol-style = native