From 11bed874c2f4f0349a8de868201d718dd0e6fa21 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Mon, 2 May 2011 15:23:22 +0000 Subject: [PATCH 01/57] LUCENE-3062: Fix test to be more tolerant and accept duplicates generated by randomRealisticUnicodeString git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1098625 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/lucene/util/TestBytesRefHash.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lucene/src/test/org/apache/lucene/util/TestBytesRefHash.java b/lucene/src/test/org/apache/lucene/util/TestBytesRefHash.java index 2c82aea6ff3..a0739372c52 100644 --- a/lucene/src/test/org/apache/lucene/util/TestBytesRefHash.java +++ b/lucene/src/test/org/apache/lucene/util/TestBytesRefHash.java @@ -135,6 +135,7 @@ public class TestBytesRefHash extends LuceneTestCase { public void testCompact() { BytesRef ref = new BytesRef(); for (int j = 0; j < 2 * RANDOM_MULTIPLIER; j++) { + int numEntries = 0; final int size = 797; BitSet bits = new BitSet(size); for (int i = 0; i < size; i++) { @@ -143,13 +144,21 @@ public class TestBytesRefHash extends LuceneTestCase { str = _TestUtil.randomRealisticUnicodeString(random, 1000); } while (str.length() == 0); ref.copy(str); - bits.set(hash.add(ref)); - + final int key = hash.add(ref); + if (key < 0) { + assertTrue(bits.get((-key)-1)); + } else { + assertFalse(bits.get(key)); + bits.set(key); + numEntries++; + } } assertEquals(hash.size(), bits.cardinality()); + assertEquals(numEntries, bits.cardinality()); + assertEquals(numEntries, hash.size()); int[] compact = hash.compact(); - assertTrue(size < compact.length); - for (int i = 0; i < size; i++) { + assertTrue(numEntries < compact.length); + for (int i = 0; i < numEntries; i++) { bits.set(compact[i], false); } assertEquals(0, bits.cardinality()); From 679cfee191306585c15bbba93c5b9f1b0e770a51 Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Mon, 2 May 2011 15:47:38 +0000 Subject: [PATCH 02/57] LUCENE-3054: PhraseQuery can in some cases stack overflow in SorterTemplate.quickSort(). This fix also adds an optimization to PhraseQuery as term with lower doc freq will also have less positions git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1098633 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/CHANGES.txt | 5 +++ .../lucene/search/MultiPhraseQuery.java | 2 +- .../org/apache/lucene/search/PhraseQuery.java | 36 +++++++++++++++++-- .../apache/lucene/util/SorterTemplate.java | 17 +++++++-- .../org/apache/lucene/util/TestArrayUtil.java | 18 ++++++++++ 5 files changed, 73 insertions(+), 5 deletions(-) diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 83380041f13..ef4b3568ea5 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -491,6 +491,11 @@ Bug fixes very special use cases of the TokenStream-API, most users would not have recognized it. (Uwe Schindler, Robert Muir) +* LUCENE-3054: PhraseQuery can in some cases stack overflow in + SorterTemplate.quickSort(). This fix also adds an optimization to + PhraseQuery as term with lower doc freq will also have less positions. + (Uwe Schindler, Robert Muir, Otis Gospodnetic) + ======================= Lucene 3.1.0 ======================= Changes in backwards compatibility policy diff --git a/lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java b/lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java index 7cb6994ccaa..8e18b520263 100644 --- a/lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java +++ b/lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java @@ -214,7 +214,7 @@ public class MultiPhraseQuery extends Query { docFreq = reader.docFreq(term.field(), term.bytes()); } - postingsFreqs[pos] = new PhraseQuery.PostingsAndFreq(postingsEnum, docFreq, positions.get(pos).intValue()); + postingsFreqs[pos] = new PhraseQuery.PostingsAndFreq(postingsEnum, docFreq, positions.get(pos).intValue(), terms[0]); } // sort by increasing docFreq order diff --git a/lucene/src/java/org/apache/lucene/search/PhraseQuery.java b/lucene/src/java/org/apache/lucene/search/PhraseQuery.java index 2c8d977fa82..a23bdbe69f6 100644 --- a/lucene/src/java/org/apache/lucene/search/PhraseQuery.java +++ b/lucene/src/java/org/apache/lucene/search/PhraseQuery.java @@ -124,16 +124,48 @@ public class PhraseQuery extends Query { final DocsAndPositionsEnum postings; final int docFreq; final int position; + final Term term; - public PostingsAndFreq(DocsAndPositionsEnum postings, int docFreq, int position) { + public PostingsAndFreq(DocsAndPositionsEnum postings, int docFreq, int position, Term term) { this.postings = postings; this.docFreq = docFreq; this.position = position; + this.term = term; } public int compareTo(PostingsAndFreq other) { + if (docFreq == other.docFreq) { + if (position == other.position) { + return term.compareTo(other.term); + } + return position - other.position; + } return docFreq - other.docFreq; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + docFreq; + result = prime * result + position; + result = prime * result + ((term == null) ? 0 : term.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + PostingsAndFreq other = (PostingsAndFreq) obj; + if (docFreq != other.docFreq) return false; + if (position != other.position) return false; + if (term == null) { + if (other.term != null) return false; + } else if (!term.equals(other.term)) return false; + return true; + } } private class PhraseWeight extends Weight { @@ -197,7 +229,7 @@ public class PhraseQuery extends Query { return null; } } - postingsFreqs[i] = new PostingsAndFreq(postingsEnum, reader.docFreq(t.field(), t.bytes()), positions.get(i).intValue()); + postingsFreqs[i] = new PostingsAndFreq(postingsEnum, reader.docFreq(t.field(), t.bytes()), positions.get(i).intValue(), t); } // sort by increasing docFreq order diff --git a/lucene/src/java/org/apache/lucene/util/SorterTemplate.java b/lucene/src/java/org/apache/lucene/util/SorterTemplate.java index b0e558c1c20..8ff57532c92 100644 --- a/lucene/src/java/org/apache/lucene/util/SorterTemplate.java +++ b/lucene/src/java/org/apache/lucene/util/SorterTemplate.java @@ -30,6 +30,7 @@ package org.apache.lucene.util; public abstract class SorterTemplate { private static final int MERGESORT_THRESHOLD = 12; + private static final int MERGE_TO_QUICKSORT_THRESHOLD = 40; private static final int QUICKSORT_THRESHOLD = 7; /** Implement this method, that swaps slots {@code i} and {@code j} in your data */ @@ -63,6 +64,10 @@ public abstract class SorterTemplate { /** Sorts via in-place, but unstable, QuickSort algorithm. * For small collections falls back to {@link #insertionSort(int,int)}. */ public final void quickSort(int lo, int hi) { + quickSort(lo, hi, MERGE_TO_QUICKSORT_THRESHOLD); + } + + private void quickSort(int lo, int hi, int maxDepth) { final int diff = hi - lo; if (diff <= QUICKSORT_THRESHOLD) { insertionSort(lo, hi); @@ -101,8 +106,16 @@ public abstract class SorterTemplate { } } - quickSort(lo, left); - quickSort(left + 1, hi); + // fall back to merge sort when recursion depth gets too big + if (maxDepth == 0) { + // for testing: new Exception("Hit recursion depth limit").printStackTrace(); + mergeSort(lo, left); + mergeSort(left + 1, hi); + } else { + --maxDepth; + quickSort(lo, left, maxDepth); + quickSort(left + 1, hi, maxDepth); + } } /** Sorts via stable in-place MergeSort algorithm diff --git a/lucene/src/test/org/apache/lucene/util/TestArrayUtil.java b/lucene/src/test/org/apache/lucene/util/TestArrayUtil.java index fc9575170e5..61e27f1e28f 100644 --- a/lucene/src/test/org/apache/lucene/util/TestArrayUtil.java +++ b/lucene/src/test/org/apache/lucene/util/TestArrayUtil.java @@ -144,6 +144,24 @@ public class TestArrayUtil extends LuceneTestCase { } } + private Integer[] createSparseRandomArray(int maxSize) { + final Integer[] a = new Integer[random.nextInt(maxSize) + 1]; + for (int i = 0; i < a.length; i++) { + a[i] = Integer.valueOf(random.nextInt(2)); + } + return a; + } + + // This is a test for LUCENE-3054 (which fails without the merge sort fall back with stack overflow in most cases) + public void testQuickToMergeSortFallback() { + for (int i = 0, c = 500 * RANDOM_MULTIPLIER; i < c; i++) { + Integer[] a1 = createSparseRandomArray(40000), a2 = a1.clone(); + ArrayUtil.quickSort(a1); + Arrays.sort(a2); + assertArrayEquals(a2, a1); + } + } + public void testMergeSort() { for (int i = 0, c = 500 * RANDOM_MULTIPLIER; i < c; i++) { Integer[] a1 = createRandomArray(1000), a2 = a1.clone(); From cb3257aed3f5dcb331ed022e25b659964624b843 Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Mon, 2 May 2011 18:53:40 +0000 Subject: [PATCH 03/57] LUCENE-3023: add Python script to diff two source trees git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1098730 13f79535-47bb-0310-9956-ffa450edef68 --- dev-tools/scripts/diffSources.py | 61 ++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 dev-tools/scripts/diffSources.py diff --git a/dev-tools/scripts/diffSources.py b/dev-tools/scripts/diffSources.py new file mode 100644 index 00000000000..8318f241cd5 --- /dev/null +++ b/dev-tools/scripts/diffSources.py @@ -0,0 +1,61 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import subprocess +import sys + +# recursive, unified output format, treat missing files as present but empty +DIFF_FLAGS = '-ruN' + +if '-skipWhitespace' in sys.argv: + sys.argv.remove('-skipWhitespace') + # ignores only whitespace changes + DIFF_FLAGS += 'bBw' + +if len(sys.argv) != 3: + print + print 'Usage: python -u diffSources.py [-skipWhitespace]' + print + print '''This tool creates an applying patch between two directories. + +While you could use this to make a committable patch from a branch, that approach loses +the svn history from the branch (better to use "svn merge --reintegrate", for example). This +diff output should not be considered "authoritative" from a merging standpoint as it does +not reflect what svn will do on merge. +''' + print + sys.exit(0) + +p = subprocess.Popen(['diff', DIFF_FLAGS, '-x', '.svn', '-x', 'build', sys.argv[1], sys.argv[2]], shell=False, stdout=subprocess.PIPE) + +keep = False +while True: + l = p.stdout.readline() + if l == '': + break + if l.endswith('\r\n'): + l = l[:-2] + elif l.endswith('\n'): + l = l[:-1] + if l.startswith('diff ') or l.startswith('Binary files '): + keep = l.lower().find('/build/') == -1 and (l.lower().startswith('Only in') or ((l.lower().endswith('.java') or l.lower().endswith('.txt') or l.lower().endswith('.xml') or l.lower().endswith('.iml')) and l.find('/.svn/') == -1)) + if keep: + print + print + print l.strip() + elif keep: + print l + elif l.startswith('Only in'): + print l.strip() From ab33f1b258b4da11212f5201945d79f809f47789 Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Mon, 2 May 2011 19:06:29 +0000 Subject: [PATCH 04/57] LUCENE-3051: don't call SegmentInfo.sizeInBytes for merging segments (it's not thread safe) git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1098740 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/lucene/index/IndexWriter.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/index/IndexWriter.java b/lucene/src/java/org/apache/lucene/index/IndexWriter.java index 826049c997f..0f0ba3e85b6 100644 --- a/lucene/src/java/org/apache/lucene/index/IndexWriter.java +++ b/lucene/src/java/org/apache/lucene/index/IndexWriter.java @@ -3133,6 +3133,16 @@ public class IndexWriter implements Closeable { message("merge seg=" + merge.info.name); } + assert merge.estimatedMergeBytes == 0; + for(SegmentInfo info : merge.segments) { + if (info.docCount > 0) { + final int delCount = numDeletedDocs(info); + assert delCount <= info.docCount; + final double delRatio = ((double) delCount)/info.docCount; + merge.estimatedMergeBytes += info.sizeInBytes(true) * (1.0 - delRatio); + } + } + // TODO: I think this should no longer be needed (we // now build CFS before adding segment to the infos); // however, on removing it, tests fail for some reason! @@ -3258,8 +3268,6 @@ public class IndexWriter implements Closeable { merge.readers = new ArrayList(); merge.readerClones = new ArrayList(); - merge.estimatedMergeBytes = 0; - // This is try/finally to make sure merger's readers are // closed: boolean success = false; @@ -3277,13 +3285,6 @@ public class IndexWriter implements Closeable { -config.getReaderTermsIndexDivisor()); merge.readers.add(reader); - final int readerMaxDoc = reader.maxDoc(); - if (readerMaxDoc > 0) { - final int delCount = reader.numDeletedDocs(); - final double delRatio = ((double) delCount)/readerMaxDoc; - merge.estimatedMergeBytes += info.sizeInBytes(true) * (1.0 - delRatio); - } - // We clone the segment readers because other // deletes may come in while we're merging so we // need readers that will not change From 60e5f02062e5e434e1d2bafa60fa1d49bc4f8f7e Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Mon, 2 May 2011 19:09:55 +0000 Subject: [PATCH 05/57] LUCENE-3059: don't leak memory in TermState for pulsing/sep codecs git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1098741 13f79535-47bb-0310-9956-ffa450edef68 --- .../pulsing/PulsingPostingsReaderImpl.java | 15 +++----- .../codecs/sep/SepPostingsReaderImpl.java | 36 ++++++++++++------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/index/codecs/pulsing/PulsingPostingsReaderImpl.java b/lucene/src/java/org/apache/lucene/index/codecs/pulsing/PulsingPostingsReaderImpl.java index 4b42caa244b..9acb75e1d85 100644 --- a/lucene/src/java/org/apache/lucene/index/codecs/pulsing/PulsingPostingsReaderImpl.java +++ b/lucene/src/java/org/apache/lucene/index/codecs/pulsing/PulsingPostingsReaderImpl.java @@ -68,15 +68,8 @@ public class PulsingPostingsReaderImpl extends PostingsReaderBase { @Override public Object clone() { - PulsingTermState clone; - clone = (PulsingTermState) super.clone(); - if (postingsSize != -1) { - clone.postings = new byte[postingsSize]; - System.arraycopy(postings, 0, clone.postings, 0, postingsSize); - } else { - assert wrappedTermState != null; - clone.wrappedTermState = (BlockTermState) wrappedTermState.clone(); - } + PulsingTermState clone = new PulsingTermState(); + clone.copyFrom(this); return clone; } @@ -90,8 +83,10 @@ public class PulsingPostingsReaderImpl extends PostingsReaderBase { postings = new byte[ArrayUtil.oversize(other.postingsSize, 1)]; } System.arraycopy(other.postings, 0, postings, 0, other.postingsSize); - } else { + } else if (wrappedTermState != null) { wrappedTermState.copyFrom(other.wrappedTermState); + } else { + wrappedTermState = (BlockTermState) other.wrappedTermState.clone(); } // NOTE: we do not copy the diff --git a/lucene/src/java/org/apache/lucene/index/codecs/sep/SepPostingsReaderImpl.java b/lucene/src/java/org/apache/lucene/index/codecs/sep/SepPostingsReaderImpl.java index 4380003b754..d6fda7627da 100644 --- a/lucene/src/java/org/apache/lucene/index/codecs/sep/SepPostingsReaderImpl.java +++ b/lucene/src/java/org/apache/lucene/index/codecs/sep/SepPostingsReaderImpl.java @@ -151,14 +151,8 @@ public class SepPostingsReaderImpl extends PostingsReaderBase { @Override public Object clone() { - SepTermState other = (SepTermState) super.clone(); - other.docIndex = (IntIndexInput.Index) docIndex.clone(); - if (freqIndex != null) { - other.freqIndex = (IntIndexInput.Index) freqIndex.clone(); - } - if (posIndex != null) { - other.posIndex = (IntIndexInput.Index) posIndex.clone(); - } + SepTermState other = new SepTermState(); + other.copyFrom(this); return other; } @@ -166,12 +160,28 @@ public class SepPostingsReaderImpl extends PostingsReaderBase { public void copyFrom(TermState _other) { super.copyFrom(_other); SepTermState other = (SepTermState) _other; - docIndex.set(other.docIndex); - if (freqIndex != null && other.freqIndex != null) { - freqIndex.set(other.freqIndex); + if (docIndex == null) { + docIndex = (IntIndexInput.Index) other.docIndex.clone(); + } else { + docIndex.set(other.docIndex); } - if (posIndex != null && other.posIndex != null) { - posIndex.set(other.posIndex); + if (other.freqIndex != null) { + if (freqIndex == null) { + freqIndex = (IntIndexInput.Index) other.freqIndex.clone(); + } else { + freqIndex.set(other.freqIndex); + } + } else { + freqIndex = null; + } + if (other.posIndex != null) { + if (posIndex == null) { + posIndex = (IntIndexInput.Index) other.posIndex.clone(); + } else { + posIndex.set(other.posIndex); + } + } else { + posIndex = null; } payloadFP = other.payloadFP; skipFP = other.skipFP; From abc9be2eef33cce5cf68f54c4cdae70272a677ab Mon Sep 17 00:00:00 2001 From: "Chris M. Hostetter" Date: Mon, 2 May 2011 19:38:20 +0000 Subject: [PATCH 06/57] SOLR-2467: Fix initialization so any errors are logged properly. git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1098760 13f79535-47bb-0310-9956-ffa450edef68 --- solr/CHANGES.txt | 3 +++ .../org/apache/solr/schema/IndexSchema.java | 19 ++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 0ed4698c902..3bef05499ef 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -198,6 +198,9 @@ Bug Fixes initialization if the schema.xml contains an analyzer configuration for a fieldType that does not use TextField. (hossman) +* SOLR-2467: Fix initialization so any errors + are logged properly. (hossman) + Other Changes ---------------------- diff --git a/solr/src/java/org/apache/solr/schema/IndexSchema.java b/solr/src/java/org/apache/solr/schema/IndexSchema.java index b6b7b6768f5..818f8d85a56 100644 --- a/solr/src/java/org/apache/solr/schema/IndexSchema.java +++ b/solr/src/java/org/apache/solr/schema/IndexSchema.java @@ -797,19 +797,23 @@ public final class IndexSchema { NamedNodeMap attrs = node.getAttributes(); String analyzerName = DOMUtil.getAttr(attrs,"class"); if (analyzerName != null) { - // No need to be core-aware as Analyzers are not in the core-aware list - final Class clazz = loader.findClass(analyzerName).asSubclass(Analyzer.class); try { + // No need to be core-aware as Analyzers are not in the core-aware list + final Class clazz = loader.findClass + (analyzerName).asSubclass(Analyzer.class); + try { - // first try to use a ctor with version parameter (needed for many new Analyzers that have no default one anymore) + // first try to use a ctor with version parameter + // (needed for many new Analyzers that have no default one anymore) Constructor cnstr = clazz.getConstructor(Version.class); final String matchVersionStr = DOMUtil.getAttr(attrs, LUCENE_MATCH_VERSION_PARAM); final Version luceneMatchVersion = (matchVersionStr == null) ? solrConfig.luceneMatchVersion : Config.parseLuceneVersionString(matchVersionStr); if (luceneMatchVersion == null) { - throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, - "Configuration Error: Analyzer '" + clazz.getName() + - "' needs a 'luceneMatchVersion' parameter"); + throw new SolrException + ( SolrException.ErrorCode.SERVER_ERROR, + "Configuration Error: Analyzer '" + clazz.getName() + + "' needs a 'luceneMatchVersion' parameter"); } return cnstr.newInstance(luceneMatchVersion); } catch (NoSuchMethodException nsme) { @@ -817,8 +821,9 @@ public final class IndexSchema { return clazz.newInstance(); } } catch (Exception e) { + log.error("Cannot load analyzer: "+analyzerName, e); throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, - "Cannot load analyzer: "+analyzerName ); + "Cannot load analyzer: "+analyzerName, e ); } } From fd0701bf4e0d4612cb44aad77c79e00f79f0fd69 Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Mon, 2 May 2011 20:39:26 +0000 Subject: [PATCH 07/57] LUCENE-3029: MultiPhraseQuery scores should not depend on docID git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1098782 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/CHANGES.txt | 4 + .../apache/lucene/search/PhrasePositions.java | 4 +- .../org/apache/lucene/search/PhraseQueue.java | 12 +- .../apache/lucene/search/PhraseScorer.java | 2 +- .../lucene/search/TestMultiPhraseQuery.java | 103 +++++++++++++++++- 5 files changed, 119 insertions(+), 6 deletions(-) diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index ef4b3568ea5..848977a1fd6 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -1477,6 +1477,10 @@ Bug fixes that warming is free to do whatever it needs to. (Earwin Burrfoot via Mike McCandless) +* LUCENE-3029: Fix corner case when MultiPhraseQuery is used with zero + position-increment tokens that would sometimes assign different + scores to identical docs. (Mike McCandless) + * LUCENE-2486: Fixed intermittent FileNotFoundException on doc store files when a mergedSegmentWarmer is set on IndexWriter. (Mike McCandless) diff --git a/lucene/src/java/org/apache/lucene/search/PhrasePositions.java b/lucene/src/java/org/apache/lucene/search/PhrasePositions.java index 303cbd166b1..00c638965cc 100644 --- a/lucene/src/java/org/apache/lucene/search/PhrasePositions.java +++ b/lucene/src/java/org/apache/lucene/search/PhrasePositions.java @@ -28,13 +28,15 @@ final class PhrasePositions { int position; // position in doc int count; // remaining pos in this doc int offset; // position in phrase + final int ord; // unique across all PhrasePositions instances final DocsAndPositionsEnum postings; // stream of docs & positions PhrasePositions next; // used to make lists boolean repeats; // there's other pp for same term (e.g. query="1st word 2nd word"~1) - PhrasePositions(DocsAndPositionsEnum postings, int o) { + PhrasePositions(DocsAndPositionsEnum postings, int o, int ord) { this.postings = postings; offset = o; + this.ord = ord; } final boolean next() throws IOException { // increments to next doc diff --git a/lucene/src/java/org/apache/lucene/search/PhraseQueue.java b/lucene/src/java/org/apache/lucene/search/PhraseQueue.java index 5b19567c59c..bac0a971d7d 100644 --- a/lucene/src/java/org/apache/lucene/search/PhraseQueue.java +++ b/lucene/src/java/org/apache/lucene/search/PhraseQueue.java @@ -30,10 +30,16 @@ final class PhraseQueue extends PriorityQueue { if (pp1.position == pp2.position) // same doc and pp.position, so decide by actual term positions. // rely on: pp.position == tp.position - offset. - return pp1.offset < pp2.offset; - else + if (pp1.offset == pp2.offset) { + return pp1.ord < pp2.ord; + } else { + return pp1.offset < pp2.offset; + } + else { return pp1.position < pp2.position; - else + } + else { return pp1.doc < pp2.doc; + } } } diff --git a/lucene/src/java/org/apache/lucene/search/PhraseScorer.java b/lucene/src/java/org/apache/lucene/search/PhraseScorer.java index 1fedc2eb3ee..da84dbcca42 100644 --- a/lucene/src/java/org/apache/lucene/search/PhraseScorer.java +++ b/lucene/src/java/org/apache/lucene/search/PhraseScorer.java @@ -55,7 +55,7 @@ abstract class PhraseScorer extends Scorer { // this allows to easily identify a matching (exact) phrase // when all PhrasePositions have exactly the same position. for (int i = 0; i < postings.length; i++) { - PhrasePositions pp = new PhrasePositions(postings[i].postings, postings[i].position); + PhrasePositions pp = new PhrasePositions(postings[i].postings, postings[i].position, i); if (last != null) { // add next to end of list last.next = pp; } else { diff --git a/lucene/src/test/org/apache/lucene/search/TestMultiPhraseQuery.java b/lucene/src/test/org/apache/lucene/search/TestMultiPhraseQuery.java index 6359ce6d27e..2cca7411064 100644 --- a/lucene/src/test/org/apache/lucene/search/TestMultiPhraseQuery.java +++ b/lucene/src/test/org/apache/lucene/search/TestMultiPhraseQuery.java @@ -25,14 +25,22 @@ import org.apache.lucene.index.MultiFields; import org.apache.lucene.search.Explanation.IDFExplanation; import org.apache.lucene.store.Directory; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.Tokenizer; +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; +import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; - +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.util.LuceneTestCase; import java.io.IOException; import java.util.Collection; import java.util.LinkedList; +import java.io.Reader; /** * This class tests the MultiPhraseQuery class. @@ -333,4 +341,97 @@ public class TestMultiPhraseQuery extends LuceneTestCase { reader.close(); indexStore.close(); } + + private static class TokenAndPos { + public final String token; + public final int pos; + public TokenAndPos(String token, int pos) { + this.token = token; + this.pos = pos; + } + } + + private static class CannedAnalyzer extends Analyzer { + private final TokenAndPos[] tokens; + + public CannedAnalyzer(TokenAndPos[] tokens) { + this.tokens = tokens; + } + + @Override + public TokenStream tokenStream(String fieldName, Reader reader) { + return new CannedTokenizer(tokens); + } + } + + private static class CannedTokenizer extends Tokenizer { + private final TokenAndPos[] tokens; + private int upto = 0; + private int lastPos = 0; + private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class); + private final PositionIncrementAttribute posIncrAtt = addAttribute(PositionIncrementAttribute.class); + + public CannedTokenizer(TokenAndPos[] tokens) { + this.tokens = tokens; + } + + @Override + public final boolean incrementToken() throws IOException { + clearAttributes(); + if (upto < tokens.length) { + final TokenAndPos token = tokens[upto++]; + termAtt.setEmpty(); + termAtt.append(token.token); + posIncrAtt.setPositionIncrement(token.pos - lastPos); + lastPos = token.pos; + return true; + } else { + return false; + } + } + } + + public void testZeroPosIncr() throws IOException { + Directory dir = new RAMDirectory(); + final TokenAndPos[] tokens = new TokenAndPos[3]; + tokens[0] = new TokenAndPos("a", 0); + tokens[1] = new TokenAndPos("b", 0); + tokens[2] = new TokenAndPos("c", 0); + + RandomIndexWriter writer = new RandomIndexWriter(random, dir, new CannedAnalyzer(tokens)); + Document doc = new Document(); + doc.add(new Field("field", "", Field.Store.NO, Field.Index.ANALYZED)); + writer.addDocument(doc); + writer.addDocument(doc); + IndexReader r = writer.getReader(); + writer.close(); + IndexSearcher s = new IndexSearcher(r); + MultiPhraseQuery mpq = new MultiPhraseQuery(); + //mpq.setSlop(1); + + // NOTE: not great that if we do the else clause here we + // get different scores! MultiPhraseQuery counts that + // phrase as occurring twice per doc (it should be 1, I + // think?). This is because MultipleTermPositions is able to + // return the same position more than once (0, in this + // case): + if (true) { + mpq.add(new Term[] {new Term("field", "b"), new Term("field", "c")}, 0); + mpq.add(new Term[] {new Term("field", "a")}, 0); + } else { + mpq.add(new Term[] {new Term("field", "a")}, 0); + mpq.add(new Term[] {new Term("field", "b"), new Term("field", "c")}, 0); + } + TopDocs hits = s.search(mpq, 2); + assert hits.totalHits == 2; + assertEquals(hits.scoreDocs[0].score, hits.scoreDocs[1].score, 1e-5); + /* + for(int hit=0;hit", ",", expand,tokFactory); + } + + /** + * @return a list of all rules + */ + protected Iterable loadRules( String synonyms, ResourceLoader loader ) { List wlist=null; try { File synonymFile = new File(synonyms); @@ -77,13 +87,12 @@ public class SynonymFilterFactory extends BaseTokenFilterFactory implements Reso } catch (IOException e) { throw new RuntimeException(e); } - synMap = new SynonymMap(ignoreCase); - parseRules(wlist, synMap, "=>", ",", expand,tokFactory); + return wlist; } private SynonymMap synMap; - static void parseRules(List rules, SynonymMap map, String mappingSep, + static void parseRules(Iterable rules, SynonymMap map, String mappingSep, String synSep, boolean expansion, TokenizerFactory tokFactory) { int count=0; for (String rule : rules) { diff --git a/solr/src/test/org/apache/solr/analysis/TestSynonymMap.java b/solr/src/test/org/apache/solr/analysis/TestSynonymMap.java index e00cd35c426..f60fe65a2ed 100644 --- a/solr/src/test/org/apache/solr/analysis/TestSynonymMap.java +++ b/solr/src/test/org/apache/solr/analysis/TestSynonymMap.java @@ -17,6 +17,8 @@ package org.apache.solr.analysis; +import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -25,6 +27,9 @@ import java.util.Map; import org.apache.lucene.analysis.Token; import org.apache.lucene.analysis.synonym.SynonymMap; import org.apache.lucene.util.LuceneTestCase; +import org.apache.solr.common.ResourceLoader; + +import visad.UnimplementedException; public class TestSynonymMap extends LuceneTestCase { @@ -257,6 +262,43 @@ public class TestSynonymMap extends LuceneTestCase { assertTokIncludes( getSubSynonymMap( getSubSynonymMap( synMap, "ab" ), "bc" ), "cd", "gh" ); } + + public void testLoadRules() throws Exception { + Map args = new HashMap(); + args.put( "synonyms", "something.txt" ); + SynonymFilterFactory ff = new SynonymFilterFactory(); + ff.init(args); + ff.inform( new ResourceLoader() { + @Override + public List getLines(String resource) throws IOException { + if( !"something.txt".equals(resource) ) { + throw new RuntimeException( "should not get a differnt resource" ); + } + List rules = new ArrayList(); + rules.add( "a,b" ); + return rules; + } + + @Override + public Object newInstance(String cname, String... subpackages) { + throw new RuntimeException("stub"); + } + + @Override + public InputStream openResource(String resource) throws IOException { + throw new RuntimeException("stub"); + } + }); + + SynonymMap synMap = ff.getSynonymMap(); + assertEquals( 2, synMap.submap.size() ); + assertTokIncludes( synMap, "a", "a" ); + assertTokIncludes( synMap, "a", "b" ); + assertTokIncludes( synMap, "b", "a" ); + assertTokIncludes( synMap, "b", "b" ); + } + + private void assertTokIncludes( SynonymMap map, String src, String exp ) throws Exception { Token[] tokens = map.submap.get( src ).synonyms; boolean inc = false; From e5256e71e280c86eed45fae98e5b5a2e4b14ba07 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Mon, 2 May 2011 23:36:16 +0000 Subject: [PATCH 09/57] SOLR-2484: make SynonymFilterFactory more extensible git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1098860 13f79535-47bb-0310-9956-ffa450edef68 --- solr/src/test/org/apache/solr/analysis/TestSynonymMap.java | 1 - 1 file changed, 1 deletion(-) diff --git a/solr/src/test/org/apache/solr/analysis/TestSynonymMap.java b/solr/src/test/org/apache/solr/analysis/TestSynonymMap.java index f60fe65a2ed..d3a6ee77873 100644 --- a/solr/src/test/org/apache/solr/analysis/TestSynonymMap.java +++ b/solr/src/test/org/apache/solr/analysis/TestSynonymMap.java @@ -29,7 +29,6 @@ import org.apache.lucene.analysis.synonym.SynonymMap; import org.apache.lucene.util.LuceneTestCase; import org.apache.solr.common.ResourceLoader; -import visad.UnimplementedException; public class TestSynonymMap extends LuceneTestCase { From 4455345c6e00f31479142745761686db5a0dfb0c Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Tue, 3 May 2011 00:29:47 +0000 Subject: [PATCH 10/57] LUCENE-3063: factor CharTokenizer/CharacterUtils into analyzers module git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1098871 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/MIGRATE.txt | 2 + .../apache/lucene/analysis/MockTokenizer.java | 63 +++++++++++++++++-- .../apache/lucene/index/TestIndexWriter.java | 2 +- .../lucene/index/TestStressIndexing2.java | 9 +-- modules/analysis/CHANGES.txt | 2 + .../analysis/ar/ArabicLetterTokenizer.java | 2 +- .../lucene/analysis/core/LetterTokenizer.java | 2 +- .../lucene/analysis/core/LowerCaseFilter.java | 2 +- .../analysis/core/LowerCaseTokenizer.java | 2 +- .../lucene/analysis/core/SimpleAnalyzer.java | 2 +- .../analysis/core/WhitespaceAnalyzer.java | 2 +- .../analysis/core/WhitespaceTokenizer.java | 2 +- .../analysis/el/GreekLowerCaseFilter.java | 2 +- .../lucene/analysis/in/IndicTokenizer.java | 2 +- .../analysis/ru/RussianLetterTokenizer.java | 2 +- .../lucene/analysis/util/CharArrayMap.java | 2 +- .../lucene/analysis/util}/CharTokenizer.java | 7 ++- .../lucene/analysis}/util/CharacterUtils.java | 4 +- .../analysis/util}/TestCharTokenizers.java | 14 +++-- .../analysis}/util/TestCharacterUtils.java | 6 +- 20 files changed, 95 insertions(+), 36 deletions(-) rename {lucene/src/java/org/apache/lucene/analysis => modules/analysis/common/src/java/org/apache/lucene/analysis/util}/CharTokenizer.java (97%) rename {lucene/src/java/org/apache/lucene => modules/analysis/common/src/java/org/apache/lucene/analysis}/util/CharacterUtils.java (99%) rename {lucene/src/test/org/apache/lucene/analysis => modules/analysis/common/src/test/org/apache/lucene/analysis/util}/TestCharTokenizers.java (82%) rename {lucene/src/test/org/apache/lucene => modules/analysis/common/src/test/org/apache/lucene/analysis}/util/TestCharacterUtils.java (97%) diff --git a/lucene/MIGRATE.txt b/lucene/MIGRATE.txt index 779b6309a44..c2666e06784 100644 --- a/lucene/MIGRATE.txt +++ b/lucene/MIGRATE.txt @@ -312,6 +312,8 @@ LUCENE-1458, LUCENE-2111: Flexible Indexing - o.a.l.analysis.ReusableAnalyzerBase -> o.a.l.analysis.util.ReusableAnalyzerBase - o.a.l.analysis.StopwordAnalyzerBase -> o.a.l.analysis.util.StopwordAnalyzerBase - o.a.l.analysis.WordListLoader -> o.a.l.analysis.util.WordListLoader + - o.a.l.analysis.CharTokenizer -> o.a.l.analysis.util.CharTokenizer + - o.a.l.util.CharacterUtils -> o.a.l.analysis.util.CharacterUtils * LUCENE-2514: The option to use a Collator's order (instead of binary order) for sorting and range queries has been moved to contrib/queries. diff --git a/lucene/src/test-framework/org/apache/lucene/analysis/MockTokenizer.java b/lucene/src/test-framework/org/apache/lucene/analysis/MockTokenizer.java index 6e4f30b3968..f5bc45996a0 100644 --- a/lucene/src/test-framework/org/apache/lucene/analysis/MockTokenizer.java +++ b/lucene/src/test-framework/org/apache/lucene/analysis/MockTokenizer.java @@ -20,14 +20,15 @@ package org.apache.lucene.analysis; import java.io.IOException; import java.io.Reader; -import org.apache.lucene.util.LuceneTestCase; +import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; +import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; import org.apache.lucene.util.automaton.CharacterRunAutomaton; import org.apache.lucene.util.automaton.RegExp; /** * Automaton-based tokenizer for testing. Optionally lowercases. */ -public class MockTokenizer extends CharTokenizer { +public class MockTokenizer extends Tokenizer { /** Acts Similar to WhitespaceTokenizer */ public static final CharacterRunAutomaton WHITESPACE = new CharacterRunAutomaton(new RegExp("[^ \t\r\n]+").toAutomaton()); @@ -45,21 +46,67 @@ public class MockTokenizer extends CharTokenizer { private final boolean lowerCase; private int state; + private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class); + private final OffsetAttribute offsetAtt = addAttribute(OffsetAttribute.class); + int off = 0; + public MockTokenizer(AttributeFactory factory, Reader input, CharacterRunAutomaton runAutomaton, boolean lowerCase) { - super(LuceneTestCase.TEST_VERSION_CURRENT, factory, input); + super(factory, input); this.runAutomaton = runAutomaton; this.lowerCase = lowerCase; this.state = runAutomaton.getInitialState(); } public MockTokenizer(Reader input, CharacterRunAutomaton runAutomaton, boolean lowerCase) { - super(LuceneTestCase.TEST_VERSION_CURRENT, input); + super(input); this.runAutomaton = runAutomaton; this.lowerCase = lowerCase; this.state = runAutomaton.getInitialState(); } @Override + public final boolean incrementToken() throws IOException { + clearAttributes(); + for (;;) { + int startOffset = off; + int cp = readCodePoint(); + if (cp < 0) { + break; + } else if (isTokenChar(cp)) { + int endOffset; + do { + char chars[] = Character.toChars(normalize(cp)); + for (int i = 0; i < chars.length; i++) + termAtt.append(chars[i]); + endOffset = off; + cp = readCodePoint(); + } while (cp >= 0 && isTokenChar(cp)); + offsetAtt.setOffset(startOffset, endOffset); + return true; + } + } + return false; + } + + protected int readCodePoint() throws IOException { + int ch = input.read(); + if (ch < 0) { + return ch; + } else { + assert !Character.isLowSurrogate((char) ch); + off++; + if (Character.isHighSurrogate((char) ch)) { + int ch2 = input.read(); + if (ch2 >= 0) { + off++; + assert Character.isLowSurrogate((char) ch2); + return Character.toCodePoint((char) ch, (char) ch2); + } + } + return ch; + } + } + protected boolean isTokenChar(int c) { state = runAutomaton.step(state, c); if (state < 0) { @@ -70,7 +117,6 @@ public class MockTokenizer extends CharTokenizer { } } - @Override protected int normalize(int c) { return lowerCase ? Character.toLowerCase(c) : c; } @@ -79,5 +125,12 @@ public class MockTokenizer extends CharTokenizer { public void reset() throws IOException { super.reset(); state = runAutomaton.getInitialState(); + off = 0; + } + + @Override + public void end() throws IOException { + int finalOffset = correctOffset(off); + offsetAtt.setOffset(finalOffset, finalOffset); } } diff --git a/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java b/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java index e6f27030134..90bf1cacc6d 100644 --- a/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java +++ b/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java @@ -1603,7 +1603,7 @@ public class TestIndexWriter extends LuceneTestCase { // LUCENE-510 public void testInvalidUTF16() throws Throwable { Directory dir = newDirectory(); - IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random))); + IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new StringSplitAnalyzer())); Document doc = new Document(); final int count = utf8Data.length/2; diff --git a/lucene/src/test/org/apache/lucene/index/TestStressIndexing2.java b/lucene/src/test/org/apache/lucene/index/TestStressIndexing2.java index a0fbe6d1f55..8eb6224805f 100644 --- a/lucene/src/test/org/apache/lucene/index/TestStressIndexing2.java +++ b/lucene/src/test/org/apache/lucene/index/TestStressIndexing2.java @@ -616,7 +616,7 @@ public class TestStressIndexing2 extends LuceneTestCase { } for(int i=start;i o.a.l.analysis.util.ReusableAnalyzerBase - o.a.l.analysis.StopwordAnalyzerBase -> o.a.l.analysis.util.StopwordAnalyzerBase - o.a.l.analysis.WordListLoader -> o.a.l.analysis.util.WordListLoader + - o.a.l.analysis.CharTokenizer -> o.a.l.analysis.util.CharTokenizer + - o.a.l.util.CharacterUtils -> o.a.l.analysis.util.CharacterUtils * SOLR-1057: Add PathHierarchyTokenizer that represents file path hierarchies as synonyms of /something, /something/something, /something/something/else. (Ryan McKinley, Koji Sekiguchi) diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/ar/ArabicLetterTokenizer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/ar/ArabicLetterTokenizer.java index 26f06d3ffa0..fff6148d19a 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/ar/ArabicLetterTokenizer.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/ar/ArabicLetterTokenizer.java @@ -18,8 +18,8 @@ package org.apache.lucene.analysis.ar; import java.io.Reader; -import org.apache.lucene.analysis.CharTokenizer; import org.apache.lucene.analysis.core.LetterTokenizer; +import org.apache.lucene.analysis.util.CharTokenizer; import org.apache.lucene.analysis.standard.StandardTokenizer; // javadoc @link import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.Version; diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LetterTokenizer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LetterTokenizer.java index a9853386d53..3bf349719d7 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LetterTokenizer.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LetterTokenizer.java @@ -19,8 +19,8 @@ package org.apache.lucene.analysis.core; import java.io.Reader; -import org.apache.lucene.analysis.CharTokenizer; import org.apache.lucene.analysis.Tokenizer; +import org.apache.lucene.analysis.util.CharTokenizer; import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.Version; diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LowerCaseFilter.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LowerCaseFilter.java index c10972b701b..0e1c7e616fb 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LowerCaseFilter.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LowerCaseFilter.java @@ -22,7 +22,7 @@ import java.io.IOException; import org.apache.lucene.analysis.TokenFilter; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; -import org.apache.lucene.util.CharacterUtils; +import org.apache.lucene.analysis.util.CharacterUtils; import org.apache.lucene.util.Version; /** diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LowerCaseTokenizer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LowerCaseTokenizer.java index a65d90b4ffa..ecdf550eb85 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LowerCaseTokenizer.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/LowerCaseTokenizer.java @@ -19,8 +19,8 @@ package org.apache.lucene.analysis.core; import java.io.Reader; -import org.apache.lucene.analysis.CharTokenizer; import org.apache.lucene.analysis.Tokenizer; +import org.apache.lucene.analysis.util.CharTokenizer; import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.Version; diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/SimpleAnalyzer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/SimpleAnalyzer.java index ce2bc6abd7c..31cfa1e00dc 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/SimpleAnalyzer.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/SimpleAnalyzer.java @@ -20,7 +20,7 @@ package org.apache.lucene.analysis.core; import java.io.Reader; import org.apache.lucene.analysis.Analyzer; -import org.apache.lucene.analysis.CharTokenizer; +import org.apache.lucene.analysis.util.CharTokenizer; import org.apache.lucene.analysis.util.ReusableAnalyzerBase; import org.apache.lucene.util.Version; diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/WhitespaceAnalyzer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/WhitespaceAnalyzer.java index 85ce28efc99..357350cef38 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/WhitespaceAnalyzer.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/WhitespaceAnalyzer.java @@ -19,7 +19,7 @@ package org.apache.lucene.analysis.core; import java.io.Reader; -import org.apache.lucene.analysis.CharTokenizer; +import org.apache.lucene.analysis.util.CharTokenizer; import org.apache.lucene.analysis.util.ReusableAnalyzerBase; import org.apache.lucene.util.Version; diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/WhitespaceTokenizer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/WhitespaceTokenizer.java index 4bf4f049dee..01004c68ca5 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/core/WhitespaceTokenizer.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/core/WhitespaceTokenizer.java @@ -19,8 +19,8 @@ package org.apache.lucene.analysis.core; import java.io.Reader; -import org.apache.lucene.analysis.CharTokenizer; import org.apache.lucene.analysis.Tokenizer; +import org.apache.lucene.analysis.util.CharTokenizer; import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.Version; diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/el/GreekLowerCaseFilter.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/el/GreekLowerCaseFilter.java index 1fed10384da..01c537b85cb 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/el/GreekLowerCaseFilter.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/el/GreekLowerCaseFilter.java @@ -21,7 +21,7 @@ import java.io.IOException; import org.apache.lucene.analysis.TokenFilter; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; -import org.apache.lucene.util.CharacterUtils; +import org.apache.lucene.analysis.util.CharacterUtils; import org.apache.lucene.util.Version; /** diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/in/IndicTokenizer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/in/IndicTokenizer.java index f89b07a3cbc..2e4c6e43e3f 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/in/IndicTokenizer.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/in/IndicTokenizer.java @@ -19,7 +19,7 @@ package org.apache.lucene.analysis.in; import java.io.Reader; -import org.apache.lucene.analysis.CharTokenizer; +import org.apache.lucene.analysis.util.CharTokenizer; import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.Version; diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/ru/RussianLetterTokenizer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/ru/RussianLetterTokenizer.java index e5426d775b2..088b8025064 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/ru/RussianLetterTokenizer.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/ru/RussianLetterTokenizer.java @@ -18,8 +18,8 @@ package org.apache.lucene.analysis.ru; */ import java.io.Reader; -import org.apache.lucene.analysis.CharTokenizer; import org.apache.lucene.analysis.Tokenizer; // for javadocs +import org.apache.lucene.analysis.util.CharTokenizer; import org.apache.lucene.analysis.core.LetterTokenizer; import org.apache.lucene.analysis.standard.StandardTokenizer; // for javadocs import org.apache.lucene.util.AttributeSource; diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/util/CharArrayMap.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/util/CharArrayMap.java index cd52e392070..552ea3fd3dd 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/util/CharArrayMap.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/util/CharArrayMap.java @@ -24,7 +24,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; -import org.apache.lucene.util.CharacterUtils; +import org.apache.lucene.analysis.util.CharacterUtils; import org.apache.lucene.util.Version; diff --git a/lucene/src/java/org/apache/lucene/analysis/CharTokenizer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/util/CharTokenizer.java similarity index 97% rename from lucene/src/java/org/apache/lucene/analysis/CharTokenizer.java rename to modules/analysis/common/src/java/org/apache/lucene/analysis/util/CharTokenizer.java index 3055d19e5b2..5d91a3a3fe1 100644 --- a/lucene/src/java/org/apache/lucene/analysis/CharTokenizer.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/util/CharTokenizer.java @@ -1,4 +1,4 @@ -package org.apache.lucene.analysis; +package org.apache.lucene.analysis.util; /** * Licensed to the Apache Software Foundation (ASF) under one or more @@ -20,12 +20,13 @@ package org.apache.lucene.analysis; import java.io.IOException; import java.io.Reader; +import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.util.AttributeSource; -import org.apache.lucene.util.CharacterUtils; +import org.apache.lucene.analysis.util.CharacterUtils; import org.apache.lucene.util.Version; -import org.apache.lucene.util.CharacterUtils.CharacterBuffer; +import org.apache.lucene.analysis.util.CharacterUtils.CharacterBuffer; /** * An abstract base class for simple, character-oriented tokenizers. diff --git a/lucene/src/java/org/apache/lucene/util/CharacterUtils.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/util/CharacterUtils.java similarity index 99% rename from lucene/src/java/org/apache/lucene/util/CharacterUtils.java rename to modules/analysis/common/src/java/org/apache/lucene/analysis/util/CharacterUtils.java index 8f5a8af9ede..fe622788198 100644 --- a/lucene/src/java/org/apache/lucene/util/CharacterUtils.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/util/CharacterUtils.java @@ -1,8 +1,10 @@ -package org.apache.lucene.util; +package org.apache.lucene.analysis.util; import java.io.IOException; import java.io.Reader; +import org.apache.lucene.util.Version; + /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with diff --git a/lucene/src/test/org/apache/lucene/analysis/TestCharTokenizers.java b/modules/analysis/common/src/test/org/apache/lucene/analysis/util/TestCharTokenizers.java similarity index 82% rename from lucene/src/test/org/apache/lucene/analysis/TestCharTokenizers.java rename to modules/analysis/common/src/test/org/apache/lucene/analysis/util/TestCharTokenizers.java index adb902d95f6..f129596df92 100644 --- a/lucene/src/test/org/apache/lucene/analysis/TestCharTokenizers.java +++ b/modules/analysis/common/src/test/org/apache/lucene/analysis/util/TestCharTokenizers.java @@ -1,4 +1,4 @@ -package org.apache.lucene.analysis; +package org.apache.lucene.analysis.util; /** * Licensed to the Apache Software Foundation (ASF) under one or more @@ -20,6 +20,10 @@ package org.apache.lucene.analysis; import java.io.IOException; import java.io.StringReader; +import org.apache.lucene.analysis.BaseTokenStreamTestCase; +import org.apache.lucene.analysis.Tokenizer; +import org.apache.lucene.analysis.core.LowerCaseTokenizer; + /** * Testcase for {@link CharTokenizer} subclasses @@ -42,7 +46,7 @@ public class TestCharTokenizers extends BaseTokenStreamTestCase { } // internal buffer size is 1024 make sure we have a surrogate pair right at the border builder.insert(1023, "\ud801\udc1c"); - MockTokenizer tokenizer = new MockTokenizer(new StringReader(builder.toString()), MockTokenizer.SIMPLE, true); + Tokenizer tokenizer = new LowerCaseTokenizer(TEST_VERSION_CURRENT, new StringReader(builder.toString())); assertTokenStreamContents(tokenizer, builder.toString().toLowerCase().split(" ")); } @@ -59,7 +63,7 @@ public class TestCharTokenizers extends BaseTokenStreamTestCase { builder.append("a"); } builder.append("\ud801\udc1cabc"); - MockTokenizer tokenizer = new MockTokenizer(new StringReader(builder.toString()), MockTokenizer.SIMPLE, true); + Tokenizer tokenizer = new LowerCaseTokenizer(TEST_VERSION_CURRENT, new StringReader(builder.toString())); assertTokenStreamContents(tokenizer, new String[] {builder.toString().toLowerCase()}); } } @@ -73,7 +77,7 @@ public class TestCharTokenizers extends BaseTokenStreamTestCase { for (int i = 0; i < 255; i++) { builder.append("A"); } - MockTokenizer tokenizer = new MockTokenizer(new StringReader(builder.toString() + builder.toString()), MockTokenizer.SIMPLE, true); + Tokenizer tokenizer = new LowerCaseTokenizer(TEST_VERSION_CURRENT, new StringReader(builder.toString() + builder.toString())); assertTokenStreamContents(tokenizer, new String[] {builder.toString().toLowerCase(), builder.toString().toLowerCase()}); } @@ -87,7 +91,7 @@ public class TestCharTokenizers extends BaseTokenStreamTestCase { builder.append("A"); } builder.append("\ud801\udc1c"); - MockTokenizer tokenizer = new MockTokenizer(new StringReader(builder.toString() + builder.toString()), MockTokenizer.SIMPLE, true); + Tokenizer tokenizer = new LowerCaseTokenizer(TEST_VERSION_CURRENT, new StringReader(builder.toString() + builder.toString())); assertTokenStreamContents(tokenizer, new String[] {builder.toString().toLowerCase(), builder.toString().toLowerCase()}); } } diff --git a/lucene/src/test/org/apache/lucene/util/TestCharacterUtils.java b/modules/analysis/common/src/test/org/apache/lucene/analysis/util/TestCharacterUtils.java similarity index 97% rename from lucene/src/test/org/apache/lucene/util/TestCharacterUtils.java rename to modules/analysis/common/src/test/org/apache/lucene/analysis/util/TestCharacterUtils.java index 69393bca871..4e9fdbf6c24 100644 --- a/lucene/src/test/org/apache/lucene/util/TestCharacterUtils.java +++ b/modules/analysis/common/src/test/org/apache/lucene/analysis/util/TestCharacterUtils.java @@ -1,4 +1,4 @@ -package org.apache.lucene.util; +package org.apache.lucene.analysis.util; /** * Licensed to the Apache Software Foundation (ASF) under one or more @@ -21,7 +21,9 @@ import java.io.IOException; import java.io.Reader; import java.io.StringReader; -import org.apache.lucene.util.CharacterUtils.CharacterBuffer; +import org.apache.lucene.analysis.util.CharacterUtils.CharacterBuffer; +import org.apache.lucene.util.LuceneTestCase; +import org.apache.lucene.util.Version; import org.junit.Test; /** From 294156cbfc60085f18f8646c258aca33d6f44c17 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Tue, 3 May 2011 04:57:12 +0000 Subject: [PATCH 11/57] SOLR-2485: remove BaseResponseWriter and Generic*Writer git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1098905 13f79535-47bb-0310-9956-ffa450edef68 --- .../solr/response/BaseResponseWriter.java | 319 ------------------ .../response/GenericBinaryResponseWriter.java | 88 ----- .../response/GenericTextResponseWriter.java | 80 ----- 3 files changed, 487 deletions(-) delete mode 100644 solr/src/java/org/apache/solr/response/BaseResponseWriter.java delete mode 100644 solr/src/java/org/apache/solr/response/GenericBinaryResponseWriter.java delete mode 100644 solr/src/java/org/apache/solr/response/GenericTextResponseWriter.java diff --git a/solr/src/java/org/apache/solr/response/BaseResponseWriter.java b/solr/src/java/org/apache/solr/response/BaseResponseWriter.java deleted file mode 100644 index 696903b198a..00000000000 --- a/solr/src/java/org/apache/solr/response/BaseResponseWriter.java +++ /dev/null @@ -1,319 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.solr.response; - -import org.apache.solr.common.util.NamedList; -import org.apache.solr.common.SolrDocumentList; -import org.apache.solr.common.SolrDocument; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.common.params.CommonParams; -import org.apache.solr.request.SolrQueryRequest; -import org.apache.solr.search.DocList; -import org.apache.solr.search.ReturnFields; -import org.apache.solr.search.SolrIndexSearcher; -import org.apache.solr.search.DocIterator; -import org.apache.solr.schema.FieldType; -import org.apache.solr.schema.IndexSchema; -import org.apache.solr.schema.SchemaField; - -import org.apache.lucene.document.Document; -import org.apache.lucene.document.Fieldable; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.List; -import java.util.ArrayList; - -/** - * THIS HAS NO TESTS and is not used anywhere.... no idea how or if it should work... - * - * I think we should drop it - along with {@link GenericBinaryResponseWriter} and {@link GenericBinaryResponseWriter} - * - * unless I'm missing something (ryan, March 2011) - * - * - * This class serves as a basis from which {@link QueryResponseWriter}s can be - * developed. The class provides a single method - * {@link #write(SingleResponseWriter, SolrQueryRequest, SolrQueryResponse)} - * that allows users to implement a {@link SingleResponseWriter} sub-class which - * defines how to output {@link SolrInputDocument}s or a - * {@link SolrDocumentList}. - * - * @version $Id$ - * @since 1.5 - * - */ -public abstract class BaseResponseWriter { - - private static final Logger LOG = LoggerFactory - .getLogger(BaseResponseWriter.class); - - - /** - * - * The main method that allows users to write {@link SingleResponseWriter}s - * and provide them as the initial parameter responseWriter to - * this method which defines how output should be generated. - * - * @param responseWriter - * The user-provided {@link SingleResponseWriter} implementation. - * @param request - * The provided {@link SolrQueryRequest}. - * @param response - * The provided {@link SolrQueryResponse}. - * @throws IOException - * If any error occurs. - */ - public void write(SingleResponseWriter responseWriter, - SolrQueryRequest request, SolrQueryResponse response) throws IOException { - responseWriter.start(); - NamedList nl = response.getValues(); - for (int i = 0; i < nl.size(); i++) { - String name = nl.getName(i); - Object val = nl.getVal(i); - if ("responseHeader".equals(name)) { - Boolean omitHeader = request.getParams().getBool(CommonParams.OMIT_HEADER); - if (omitHeader == null || !omitHeader) responseWriter.writeResponseHeader((NamedList) val); - } else if (val instanceof SolrDocumentList) { - SolrDocumentList list = (SolrDocumentList) val; - DocListInfo info = new DocListInfo((int)list.getNumFound(), list.size(), (int)list.getStart(), list.getMaxScore()); - if (responseWriter.isStreamingDocs()) { - responseWriter.startDocumentList(name,info); - for (SolrDocument solrDocument : list) - responseWriter.writeDoc(solrDocument); - responseWriter.endDocumentList(); - } else { - responseWriter.writeAllDocs(info, list); - } - } else if (val instanceof DocList) { - DocList docList = (DocList) val; - int sz = docList.size(); - IdxInfo idxInfo = new IdxInfo(request.getSchema(), request - .getSearcher(), response.getReturnFields()); - DocListInfo info = new DocListInfo(docList.matches(), docList.size(),docList.offset(), - docList.maxScore()); - DocIterator iterator = docList.iterator(); - if (responseWriter.isStreamingDocs()) { - responseWriter.startDocumentList(name,info); - for (int j = 0; j < sz; j++) { - SolrDocument sdoc = getDoc(iterator.nextDoc(), idxInfo); - responseWriter.writeDoc(sdoc); - } - } else { - ArrayList list = new ArrayList(docList - .size()); - for (int j = 0; j < sz; j++) { - SolrDocument sdoc = getDoc(iterator.nextDoc(), idxInfo); - list.add(sdoc); - } - responseWriter.writeAllDocs(info, list); - } - - } else { - responseWriter.writeOther(name, val); - - } - } - responseWriter.end(); - - } - - /**No ops implementation so that the implementing classes do not have to do it - */ - public void init(NamedList args){} - - private static class IdxInfo { - IndexSchema schema; - SolrIndexSearcher searcher; - ReturnFields returnFields; - - private IdxInfo(IndexSchema schema, SolrIndexSearcher searcher, - ReturnFields returnFields) { - this.schema = schema; - this.searcher = searcher; - this.returnFields = returnFields; - } - } - - private static SolrDocument getDoc(int id, IdxInfo info) throws IOException { - Document doc = info.searcher.doc(id); - SolrDocument solrDoc = new SolrDocument(); - for (Fieldable f : doc.getFields()) { - String fieldName = f.name(); - if (info.returnFields != null && !info.returnFields.wantsField(fieldName)) - continue; - SchemaField sf = info.schema.getFieldOrNull(fieldName); - FieldType ft = null; - if (sf != null) ft = sf.getType(); - Object val = null; - if (ft == null) { // handle fields not in the schema - if (f.isBinary()) - val = f.getBinaryValue(); - else - val = f.stringValue(); - } else { - try { - if (BinaryResponseWriter.KNOWN_TYPES.contains(ft.getClass())) { - val = ft.toObject(f); - } else { - val = ft.toExternal(f); - } - } catch (Exception e) { - // There is a chance of the underlying field not really matching the - // actual field type . So ,it can throw exception - LOG.warn("Error reading a field from document : " + solrDoc, e); - // if it happens log it and continue - continue; - } - } - if (sf != null && sf.multiValued() && !solrDoc.containsKey(fieldName)) { - ArrayList l = new ArrayList(); - l.add(val); - solrDoc.addField(fieldName, l); - } else { - solrDoc.addField(fieldName, val); - } - } - - return solrDoc; - } - - public static class DocListInfo { - public final int numFound; - public final int start ; - public Float maxScore = null; - public final int size; - - public DocListInfo(int numFound, int sz,int start, Float maxScore) { - this.numFound = numFound; - size = sz; - this.start = start; - this.maxScore = maxScore; - } - } - - /** - * - * Users wanting to define custom {@link QueryResponseWriter}s that deal with - * {@link SolrInputDocument}s and {@link SolrDocumentList} should override the - * methods for this class. All the methods are w/o body because the user is left - * to choose which all methods are required for his purpose - */ - public static abstract class SingleResponseWriter { - - /** - * This method is called at the start of the {@link QueryResponseWriter} - * output. Override this method if you want to provide a header for your - * output, e.g., XML headers, etc. - * - * @throws IOException - * if any error occurs. - */ - public void start() throws IOException { } - - /** - * This method is called at the start of processing a - * {@link SolrDocumentList}. Those that override this method are provided - * with {@link DocListInfo} object to use to inspect the output - * {@link SolrDocumentList}. - * - * @param info Information about the {@link SolrDocumentList} to output. - */ - public void startDocumentList(String name, DocListInfo info) throws IOException { } - - /** - * This method writes out a {@link SolrDocument}, on a doc-by-doc basis. - * This method is only called when {@link #isStreamingDocs()} returns true. - * - * @param solrDocument - * The doc-by-doc {@link SolrDocument} to transform into output as - * part of this {@link QueryResponseWriter}. - */ - public void writeDoc(SolrDocument solrDocument) throws IOException { } - - /** - * This method is called at the end of outputting a {@link SolrDocumentList} - * or on a doc-by-doc {@link SolrDocument} basis. - */ - public void endDocumentList() throws IOException { } - /** - * This method defines how to output the {@link SolrQueryResponse} header - * which is provided as a {@link NamedList} parameter. - * - * @param responseHeader - * The response header to output. - */ - public void writeResponseHeader(NamedList responseHeader) throws IOException { } - - /** - * This method is called at the end of the {@link QueryResponseWriter} - * lifecycle. Implement this method to add a footer to your output, e.g., in - * the case of XML, the outer tag for your tag set, etc. - * - * @throws IOException - * If any error occurs. - */ - public void end() throws IOException { } - - /** - * Define this method to control how output is written by this - * {@link QueryResponseWriter} if the output is not a - * {@link SolrInputDocument} or a {@link SolrDocumentList}. - * - * @param name - * The name of the object to output. - * @param other - * The object to output. - * @throws IOException - * If any error occurs. - */ - public void writeOther(String name, Object other) throws IOException { } - - /** - * Overriding this method to return false forces all - * {@link SolrInputDocument}s to be spit out as a {@link SolrDocumentList} - * so they can be processed as a whole, rather than on a doc-by-doc basis. - * If set to false, this method calls - * {@link #writeAllDocs(BaseResponseWriter.DocListInfo, List)}, else if set to true, then this - * method forces calling {@link #writeDoc(SolrDocument)} on a doc-by-doc - * basis. one - * - * @return True to force {@link #writeDoc(SolrDocument)} to be called, False - * to force {@link #writeAllDocs(BaseResponseWriter.DocListInfo, List)} to be called. - */ - public boolean isStreamingDocs() { return true; } - - /** - * Writes out all {@link SolrInputDocument}s . This is invoked only if - * {@link #isStreamingDocs()} returns false. - * - * @param info - * Information about the {@link List} of {@link SolrDocument}s to - * output. - * @param allDocs - * A {@link List} of {@link SolrDocument}s to output. - * @throws IOException - * If any error occurs. - */ - public void writeAllDocs(DocListInfo info, List allDocs) throws IOException { } - - } - -} diff --git a/solr/src/java/org/apache/solr/response/GenericBinaryResponseWriter.java b/solr/src/java/org/apache/solr/response/GenericBinaryResponseWriter.java deleted file mode 100644 index 1ce707ce4e8..00000000000 --- a/solr/src/java/org/apache/solr/response/GenericBinaryResponseWriter.java +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.solr.response; - -import java.io.OutputStream; -import java.io.IOException; -import java.io.Writer; - -import org.apache.solr.common.SolrDocumentList; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.request.SolrQueryRequest; - -import org.apache.solr.response.BaseResponseWriter.SingleResponseWriter; // javadocs - -/** - * - * - * A generic {@link QueryResponseWriter} implementation that requires a user to - * implement the - * {@link #getSingleResponseWriter(OutputStream, SolrQueryRequest, SolrQueryResponse)} - * that defines a {@link SingleResponseWriter} to handle the binary output. - * - * @since 1.5 - * @version $Id$ - * - */ -public abstract class GenericBinaryResponseWriter extends BaseResponseWriter - implements BinaryQueryResponseWriter { - - /** - * - * Writes the binary output data using the {@link SingleResponseWriter} - * provided by a call to - * {@link #getSingleResponseWriter(OutputStream, SolrQueryRequest, SolrQueryResponse)} - * . - * - * @param out - * The {@link OutputStream} to write the binary data to. - * @param request - * The provided {@link SolrQueryRequest}. - * @param response - * The provided {@link SolrQueryResponse}. - */ - public void write(OutputStream out, SolrQueryRequest request, - SolrQueryResponse response) throws IOException { - super.write(getSingleResponseWriter(out, request, response), request, - response); - } - - /** - * Users of this class should implement this method to define a - * {@link SingleResponseWriter} responsible for writing the binary output - * given a {@link SolrDocumentList} or doc-by-doc, given a - * {@link SolrInputDocument}. - * - * @param out - * The {@link OutputStream} to write the binary data response to. - * @param request - * The provided {@link SolrQueryRequest}. - * @param response - * The provided {@link SolrQueryResponse}. - * @return A {@link SingleResponseWriter} that will be used to generate the - * response output from this {@link QueryResponseWriter}. - */ - public abstract SingleResponseWriter getSingleResponseWriter( - OutputStream out, SolrQueryRequest request, SolrQueryResponse response); - - /**Just to throw Exception So that the eimplementing classes do not have to do the same - */ - public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) throws IOException { - throw new RuntimeException("This is a binary writer , Cannot write to a characterstream"); - } -} diff --git a/solr/src/java/org/apache/solr/response/GenericTextResponseWriter.java b/solr/src/java/org/apache/solr/response/GenericTextResponseWriter.java deleted file mode 100644 index 0b911b9f0af..00000000000 --- a/solr/src/java/org/apache/solr/response/GenericTextResponseWriter.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.solr.response; - -import java.io.Writer; -import java.io.IOException; - -import org.apache.solr.common.SolrDocumentList; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.request.SolrQueryRequest; - -import org.apache.solr.response.BaseResponseWriter.SingleResponseWriter; // javadocs - -/** - * - * - * A generic {@link QueryResponseWriter} implementation that requires a user to - * implement the - * {@link #getSingleResponseWriter(Writer, SolrQueryRequest, SolrQueryResponse)} - * that defines a {@link SingleResponseWriter} to handle plain ol' text output. - * - * @since 1.5 - * @version $Id$ - * - */ -public abstract class GenericTextResponseWriter extends BaseResponseWriter - implements QueryResponseWriter { - - /** - * - * Writes text output using the {@link SingleResponseWriter} provided by a - * call to - * {@link #getSingleResponseWriter(Writer, SolrQueryRequest, SolrQueryResponse)} - * . - * - * @param writer - * The {@link Writer} to write the text output to. - * @param request - * The provided {@link SolrQueryRequest}. - * @param response - * The provided {@link SolrQueryResponse}. - */ - public void write(Writer writer, SolrQueryRequest request, - SolrQueryResponse response) throws IOException { - super.write(getSingleResponseWriter(writer, request, response), request, - response); - } - - /** - * Users of this class should implement this method to define a - * {@link SingleResponseWriter} responsible for writing text output given a - * {@link SolrDocumentList} or doc-by-doc, given a {@link SolrInputDocument}. - * - * @param writer - * The {@link Writer} to write the text data response to. - * @param request - * The provided {@link SolrQueryRequest}. - * @param response - * The provided {@link SolrQueryResponse}. - * @return A {@link SingleResponseWriter} that will be used to generate the - * response output from this {@link QueryResponseWriter}. - */ - protected abstract SingleResponseWriter getSingleResponseWriter( - Writer writer, SolrQueryRequest request, SolrQueryResponse response); -} From 422f8dea4a2a3be733fd8aea62a1acc1d832eb6b Mon Sep 17 00:00:00 2001 From: Yonik Seeley Date: Tue, 3 May 2011 12:46:39 +0000 Subject: [PATCH 12/57] docs: use unix and windows paths in readme git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1099039 13f79535-47bb-0310-9956-ffa450edef68 --- solr/README.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/solr/README.txt b/solr/README.txt index 0a9e939128d..f9a72c0f187 100644 --- a/solr/README.txt +++ b/solr/README.txt @@ -64,18 +64,18 @@ docs/api/index.html Instructions for Building Apache Solr from Source ------------------------------------------------- -1. Download the Java SE 6 JDK (Java Development Kit) or later from http://java.sun.com. - You will need the JDK installed, and the %JAVA_HOME%\bin directory included - on your command path. To test this, issue a "java -version" command from your - shell and verify that the Java version is 1.6 or later. +1. Download the Java SE 6 JDK (Java Development Kit) or later from http://java.sun.com/ + You will need the JDK installed, and the $JAVA_HOME/bin (Windows: %JAVA_HOME%\bin) + folder included on your command path. To test this, issue a "java -version" command + from your shell (command prompt) and verify that the Java version is 1.6 or later. -2. Download the Apache Ant binary distribution (1.7.0 or greater) from http://ant.apache.org. - You will need Ant installed and the %ANT_HOME%\bin directory included on your - command path. To test this, issue a "ant -version" command from your - shell and verify that Ant is available. +2. Download the Apache Ant binary distribution (1.7.0 or greater) from http://ant.apache.org/ + You will need Ant installed and the $ANT_HOME/bin (Windows: %ANT_HOME%\bin) folder + included on your command path. To test this, issue a "ant -version" command from your + shell (command prompt) and verify that Ant is available. -3. Download the Apache Solr distribution, linked from the above - web site. Expand the distribution to a folder of your choice, e.g. c:\solr. +3. Download the Apache Solr distribution, linked from the above web site. + Unzip the distribution to a folder of your choice, e.g. C:\solr or ~/solr Alternately, you can obtain a copy of the latest Apache Solr source code directly from the Subversion repository: From 11e962d16b2a898ac3475a9f3d09fc328a9d2461 Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Tue, 3 May 2011 13:07:24 +0000 Subject: [PATCH 13/57] LUCENE-3054: fix remaining quickSort git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1099041 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/search/highlight/TokenSources.java | 2 +- .../org/apache/lucene/index/IndexReader.java | 2 +- .../lucene/search/MultiPhraseQuery.java | 2 +- .../org/apache/lucene/search/PhraseQuery.java | 2 +- .../apache/lucene/search/TopTermsRewrite.java | 2 +- .../lucene/search/spans/NearSpansOrdered.java | 2 +- .../apache/lucene/util/SorterTemplate.java | 26 +++++++++---------- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/TokenSources.java b/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/TokenSources.java index 616d9e26670..9a9294f93fd 100644 --- a/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/TokenSources.java +++ b/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/TokenSources.java @@ -231,7 +231,7 @@ public class TokenSources { if (unsortedTokens != null) { tokensInOriginalOrder = unsortedTokens.toArray(new Token[unsortedTokens .size()]); - ArrayUtil.quickSort(tokensInOriginalOrder, new Comparator() { + ArrayUtil.mergeSort(tokensInOriginalOrder, new Comparator() { public int compare(Token t1, Token t2) { if (t1.startOffset() == t2.startOffset()) return t1.endOffset() - t2.endOffset(); diff --git a/lucene/src/java/org/apache/lucene/index/IndexReader.java b/lucene/src/java/org/apache/lucene/index/IndexReader.java index 9f3494c4654..b0f87f1913b 100644 --- a/lucene/src/java/org/apache/lucene/index/IndexReader.java +++ b/lucene/src/java/org/apache/lucene/index/IndexReader.java @@ -1420,7 +1420,7 @@ public abstract class IndexReader implements Cloneable,Closeable { cfr = new CompoundFileReader(dir, filename); String [] files = cfr.listAll(); - ArrayUtil.quickSort(files); // sort the array of filename so that the output is more readable + ArrayUtil.mergeSort(files); // sort the array of filename so that the output is more readable for (int i = 0; i < files.length; ++i) { long len = cfr.fileLength(files[i]); diff --git a/lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java b/lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java index 8e18b520263..fc9598078d8 100644 --- a/lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java +++ b/lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java @@ -219,7 +219,7 @@ public class MultiPhraseQuery extends Query { // sort by increasing docFreq order if (slop == 0) { - ArrayUtil.quickSort(postingsFreqs); + ArrayUtil.mergeSort(postingsFreqs); } if (slop == 0) { diff --git a/lucene/src/java/org/apache/lucene/search/PhraseQuery.java b/lucene/src/java/org/apache/lucene/search/PhraseQuery.java index a23bdbe69f6..70adec70f7f 100644 --- a/lucene/src/java/org/apache/lucene/search/PhraseQuery.java +++ b/lucene/src/java/org/apache/lucene/search/PhraseQuery.java @@ -234,7 +234,7 @@ public class PhraseQuery extends Query { // sort by increasing docFreq order if (slop == 0) { - ArrayUtil.quickSort(postingsFreqs); + ArrayUtil.mergeSort(postingsFreqs); } if (slop == 0) { // optimize exact case diff --git a/lucene/src/java/org/apache/lucene/search/TopTermsRewrite.java b/lucene/src/java/org/apache/lucene/search/TopTermsRewrite.java index 472e99de705..24356e27bcf 100644 --- a/lucene/src/java/org/apache/lucene/search/TopTermsRewrite.java +++ b/lucene/src/java/org/apache/lucene/search/TopTermsRewrite.java @@ -134,7 +134,7 @@ public abstract class TopTermsRewrite extends TermCollectingRew final Term placeholderTerm = new Term(query.field); final Q q = getTopLevelQuery(); final ScoreTerm[] scoreTerms = stQueue.toArray(new ScoreTerm[stQueue.size()]); - ArrayUtil.quickSort(scoreTerms, scoreTermSortByTermComp); + ArrayUtil.mergeSort(scoreTerms, scoreTermSortByTermComp); for (final ScoreTerm st : scoreTerms) { final Term term = placeholderTerm.createTerm(st.bytes); assert reader.docFreq(term) == st.termState.docFreq() : "reader DF is " + reader.docFreq(term) + " vs " + st.termState.docFreq(); diff --git a/lucene/src/java/org/apache/lucene/search/spans/NearSpansOrdered.java b/lucene/src/java/org/apache/lucene/search/spans/NearSpansOrdered.java index 2bc9f87d27f..0eae1582573 100644 --- a/lucene/src/java/org/apache/lucene/search/spans/NearSpansOrdered.java +++ b/lucene/src/java/org/apache/lucene/search/spans/NearSpansOrdered.java @@ -190,7 +190,7 @@ public class NearSpansOrdered extends Spans { /** Advance the subSpans to the same document */ private boolean toSameDoc() throws IOException { - ArrayUtil.quickSort(subSpansByDoc, spanDocComparator); + ArrayUtil.mergeSort(subSpansByDoc, spanDocComparator); int firstIndex = 0; int maxDoc = subSpansByDoc[subSpansByDoc.length - 1].doc(); while (subSpansByDoc[firstIndex].doc() != maxDoc) { diff --git a/lucene/src/java/org/apache/lucene/util/SorterTemplate.java b/lucene/src/java/org/apache/lucene/util/SorterTemplate.java index 8ff57532c92..1ce4619984f 100644 --- a/lucene/src/java/org/apache/lucene/util/SorterTemplate.java +++ b/lucene/src/java/org/apache/lucene/util/SorterTemplate.java @@ -30,7 +30,6 @@ package org.apache.lucene.util; public abstract class SorterTemplate { private static final int MERGESORT_THRESHOLD = 12; - private static final int MERGE_TO_QUICKSORT_THRESHOLD = 40; private static final int QUICKSORT_THRESHOLD = 7; /** Implement this method, that swaps slots {@code i} and {@code j} in your data */ @@ -63,17 +62,26 @@ public abstract class SorterTemplate { /** Sorts via in-place, but unstable, QuickSort algorithm. * For small collections falls back to {@link #insertionSort(int,int)}. */ - public final void quickSort(int lo, int hi) { - quickSort(lo, hi, MERGE_TO_QUICKSORT_THRESHOLD); + public final void quickSort(final int lo, final int hi) { + if (hi <= lo) return; + // from Integer's Javadocs: ceil(log2(x)) = 32 - numberOfLeadingZeros(x - 1) + quickSort(lo, hi, (Integer.SIZE - Integer.numberOfLeadingZeros(hi - lo)) << 1); } private void quickSort(int lo, int hi, int maxDepth) { + // fall back to insertion when array has short length final int diff = hi - lo; if (diff <= QUICKSORT_THRESHOLD) { insertionSort(lo, hi); return; } + // fall back to merge sort when recursion depth gets too big + if (--maxDepth == 0) { + mergeSort(lo, hi); + return; + } + final int mid = lo + (diff >>> 1); if (compare(lo, mid) > 0) { @@ -106,16 +114,8 @@ public abstract class SorterTemplate { } } - // fall back to merge sort when recursion depth gets too big - if (maxDepth == 0) { - // for testing: new Exception("Hit recursion depth limit").printStackTrace(); - mergeSort(lo, left); - mergeSort(left + 1, hi); - } else { - --maxDepth; - quickSort(lo, left, maxDepth); - quickSort(left + 1, hi, maxDepth); - } + quickSort(lo, left, maxDepth); + quickSort(left + 1, hi, maxDepth); } /** Sorts via stable in-place MergeSort algorithm From 9fdf96c92bd000331516473c3c3f820c4f29c87c Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Tue, 3 May 2011 19:13:26 +0000 Subject: [PATCH 14/57] fix stale javadocs git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1099211 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/lucene/search/IndexSearcher.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/search/IndexSearcher.java b/lucene/src/java/org/apache/lucene/search/IndexSearcher.java index f199edc92c6..8429ec0c9af 100644 --- a/lucene/src/java/org/apache/lucene/search/IndexSearcher.java +++ b/lucene/src/java/org/apache/lucene/search/IndexSearcher.java @@ -46,8 +46,18 @@ import org.apache.lucene.util.ThreadInterruptedException; * *

Applications usually need only call the inherited * {@link #search(Query,int)} - * or {@link #search(Query,Filter,int)} methods. For performance reasons it is - * recommended to open only one IndexSearcher and use it for all of your searches. + * or {@link #search(Query,Filter,int)} methods. For + * performance reasons, if your index is unchanging, you + * should share a single IndexSearcher instance across + * multiple searches instead of creating a new one + * per-search. If your index has changed and you wish to + * see the changes reflected in searching, you should + * use {@link IndexReader#reopen} to obtain a new reader and + * then create a new IndexSearcher from that. Also, for + * low-latency turnaround it's best to use a near-real-time + * reader ({@link IndexReader#open(IndexWriter,boolean)}). + * Once you have a new {@link IndexReader}, it's relatively + * cheap to create a new IndexSearcher from it. * *

NOTE: {@link * IndexSearcher} instances are completely From 8b32176c0b7ce8392edf0c38cc590bf29101d580 Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Wed, 4 May 2011 07:05:47 +0000 Subject: [PATCH 15/57] SOLR-2493: SolrQueryParser was fixed to not parse the SolrConfig DOM tree on each instantiation which is a huge slowdown git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1099340 13f79535-47bb-0310-9956-ffa450edef68 --- solr/CHANGES.txt | 3 +++ solr/src/java/org/apache/solr/search/SolrQueryParser.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 3bef05499ef..831472aa7de 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -312,6 +312,9 @@ Bug Fixes did not clear all attributes so they displayed incorrect attribute values for tokens in later filter stages. (uschindler, rmuir, yonik) +* SOLR-2493: SolrQueryParser was fixed to not parse the SolrConfig DOM tree on each + instantiation which is a huge slowdown. (Stephane Bailliez via uschindler) + Other Changes ---------------------- diff --git a/solr/src/java/org/apache/solr/search/SolrQueryParser.java b/solr/src/java/org/apache/solr/search/SolrQueryParser.java index 34192b8fd8b..80db3314c7d 100644 --- a/solr/src/java/org/apache/solr/search/SolrQueryParser.java +++ b/solr/src/java/org/apache/solr/search/SolrQueryParser.java @@ -67,7 +67,7 @@ public class SolrQueryParser extends QueryParser { } public SolrQueryParser(QParser parser, String defaultField, Analyzer analyzer) { - super(parser.getReq().getCore().getSolrConfig().getLuceneVersion("luceneMatchVersion", Version.LUCENE_30), defaultField, analyzer); + super(parser.getReq().getCore().getSolrConfig().luceneMatchVersion, defaultField, analyzer); this.schema = parser.getReq().getSchema(); this.parser = parser; this.defaultField = defaultField; From 6c72ae4a02eabf4c72b1f1d8685879b429e2ad23 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Wed, 4 May 2011 17:25:29 +0000 Subject: [PATCH 16/57] LUCENE-3072: add LUCENE-2811 change to fileformats.html git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1099529 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/docs/fileformats.html | 34 +- lucene/docs/fileformats.pdf | 344 +++++++++--------- .../content/xdocs/fileformats.xml | 11 +- 3 files changed, 201 insertions(+), 188 deletions(-) diff --git a/lucene/docs/fileformats.html b/lucene/docs/fileformats.html index f4528c7d635..88fe07fa755 100644 --- a/lucene/docs/fileformats.html +++ b/lucene/docs/fileformats.html @@ -425,6 +425,9 @@ document.write("Last Published: " + document.lastModified);

In version 3.1, segments records the code version that created them. See LUCENE-2720 for details. + + Additionally segments track explicitly whether or + not they have term vectors. See LUCENE-2811 for details.

@@ -1508,7 +1511,7 @@ document.write("Last Published: " + document.lastModified); 3.1 Segments --> Format, Version, NameCounter, SegCount, <SegVersion, SegName, SegSize, DelGen, DocStoreOffset, [DocStoreSegment, DocStoreIsCompoundFile], HasSingleNormFile, NumField, NormGenNumField, - IsCompoundFile, DeletionCount, HasProx, Diagnostics>SegCount, CommitUserData, Checksum + IsCompoundFile, DeletionCount, HasProx, Diagnostics, HasVectors>SegCount, CommitUserData, Checksum

Format, NameCounter, SegCount, SegSize, NumField, @@ -1525,7 +1528,7 @@ document.write("Last Published: " + document.lastModified);

IsCompoundFile, HasSingleNormFile, - DocStoreIsCompoundFile, HasProx --> Int8 + DocStoreIsCompoundFile, HasProx, HasVectors --> Int8

CommitUserData --> Map<String,String> @@ -1634,7 +1637,10 @@ document.write("Last Published: " + document.lastModified); Lucene version, OS, Java version, why the segment was created (merge, flush, addIndexes), etc.

- +

HasVectors is 1 if this segment stores term vectors, + else it's 0. +

+

Lock File

The write lock, which is stored in the index @@ -1648,14 +1654,14 @@ document.write("Last Published: " + document.lastModified); documents). This lock file ensures that only one writer is modifying the index at a time.

- +

Deletable File

A writer dynamically computes the files that are deletable, instead, so no file is written.

- +

Compound Files

Starting with Lucene 1.4 the compound file format became default. This is simply a container for all files described in the next section @@ -1682,14 +1688,14 @@ document.write("Last Published: " + document.lastModified); - +

Per-Segment Files

The remaining files are all per-segment, and are thus defined by suffix.

- +

Fields

@@ -1883,7 +1889,7 @@ document.write("Last Published: " + document.lastModified); - +

Term Dictionary

The term dictionary is represented as two files: @@ -2075,7 +2081,7 @@ document.write("Last Published: " + document.lastModified); - +

Frequencies

The .frq file contains the lists of documents @@ -2203,7 +2209,7 @@ document.write("Last Published: " + document.lastModified); entry in level-1. In the example has entry 15 on level 1 a pointer to entry 15 on level 0 and entry 31 on level 1 a pointer to entry 31 on level 0.

- +

Positions

The .prx file contains the lists of positions that @@ -2273,7 +2279,7 @@ document.write("Last Published: " + document.lastModified); Payload. If PayloadLength is not stored, then this Payload has the same length as the Payload at the previous position.

- +

Normalization Factors

There's a single .nrm file containing all norms:

@@ -2353,7 +2359,7 @@ document.write("Last Published: " + document.lastModified);

Separate norm files are created (when adequate) for both compound and non compound segments.

- +

Term Vectors

Term Vector support is an optional on a field by @@ -2489,7 +2495,7 @@ document.write("Last Published: " + document.lastModified); - +

Deleted Documents

The .del file is optional, and only exists when a segment contains deletions. @@ -2553,7 +2559,7 @@ document.write("Last Published: " + document.lastModified);

- +

Limitations

diff --git a/lucene/docs/fileformats.pdf b/lucene/docs/fileformats.pdf index 4873eea8bae..366927b7389 100644 --- a/lucene/docs/fileformats.pdf +++ b/lucene/docs/fileformats.pdf @@ -289,10 +289,10 @@ endobj >> endobj 56 0 obj -<< /Length 661 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 662 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gaua=9lJf0&;KZQ'c_E.R0!SFO85`N<`,-^<\A5"QHat6gR%^fQh`!QW/c(=Hca/GQU.%=Gi+kWP%L&[I41cb^gip?$o[$\"le)C!\FYED`OQ9[lFGA'G:4k/ol=#[XjuNRDNG$.LpJKacNR]PbbE$+_8C6=2S#0VELZ*T3G<#t73#K%O<0k2TgQY_@I1!ps/di_YOeKgVdV\l,g=+nOsSR4%\;R_Q"=t!:p<.4O6WgJs-(oJ+j]30N/$.^`5tB_SSH]NR\6>`os%HoFB3cjj%BcXjBZF,`@:DLM;\,q9b0>]s'BnqW\/b+/MrZQR3Qhg99*9Z'Uda81GGeh^b3aSoH$D#lpBk\fIAL8%jD@gjJfDCjo2U]L=R#]N)ZLb8EV8SGd +Gaua=9lJf0&;KZQ'c_E.R0)Noa/5i4<`,-^<\J;"QHa endstream endobj 57 0 obj @@ -412,10 +412,10 @@ endobj >> endobj 77 0 obj -<< /Length 1915 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 2005 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gatm<9lo&I&A@C2n5a0K63n/#lE*X[N&taND:DM5"%7_VC5Pt]aH$/`]DN9X,\Y@AO!f)NP/-M"\,-qc^Kk,`=5R'.\V5MT=0YD'-O9eKc2Hf)CQB.s<79I%IUBeGY24#CLGF+YbuS`ZOUFD'ks"_W$!cn7&'eN`2oQ_Kc.YUhmU]D!&l!V(^)]_O]KO>&fAfONPHmg.K\jmlOHc_l@WB't)SKBITk.siFWf`6MaV?/qX_VtkNau5R6+/UAbF(=gY)Q]n^`U)+1t=E(+QLZs'cpHQUGiSH;='u;qh0Bh)KGFlIK*epr>n&LOmGj(gs"#Tq2QYkYU+:@@H:I,kQ]6/;>/C=_=[1)F@G6.o#55QgiqG.h8HWCTG[YK/GM73[d0EJ4DjF@p(pQ4T>"0;e;%,#;AhVe132Ppr+G^dWh%QdpZ>i:I,D7(i[e'pJS)b5pi/=Y;Cj^RZWp2U7Q?gsRuOhJMIC0R6'Rhq@Rc1&q1N4STWKmQLm\j6&KJDuPgVD*0JUg7uT7Ok&q%T3FI0Do(K98Z[r8[8N.-e=K;jpcMiuSjN:I6o7_C-7a]R*Mdj'J`=(0iIfWp\7N'3WJ9ATJ#Xm$T-Ub^k:f#r?R:buXC2@O!dbcF6X6:2=cD@-qd"212$MRJXL:`dm`&lER$,61(aOW=q/EGE[^8_pOl$(SkBTiJ3pJn_VC:O8/535(tFObe0!-/1`@8TTma:=NmT&ll5-?^+[MA9=FMIUj3PRf/Z7V3R]3FtLgP#3XW64MYj7%A!#Vm_;sCV#NL*!tIa#B4ZU:a3E&M9f(R3:$6HCYA@^fZ8u@dj@k[#'NSIn=,-YVlK!U/9(q]\`gSOk+Z_ap?MDgDhJJD?==%A4Dj)eTV&DbFZ^c2ba@gbK6j:gMYQ,$Qj+;Ej8k_/jh@QEU/CsEeE"GG].l%@QSog16^iVHoE<>:JlAnWd?H[3K,"0%@n)r)g]?]Ddd(sk"@i3IpHkg[p,.@iHM'uuFGe"L!]T\'Gf*m\5%]9$[8%U3?%)V!jX'a\39>CU$_BE;76YOf)IC>%j48*>gkdUr(6)e__^VkJe>FS%7'gP4<=,0\%HJ1nhI?FSb/:J@Oprf2iKS,#bd"=AG3aVMKj$39!hpN:$S6N#$hfO`M@U.5M$IB2@;mB'N&f$)2-6='/PQDX4CN[W]&!)PAs[u]Q-cg2M.,se)IRhtk4_t_*e/S*Q@a.LYdjFbP%QEsReO]C$6P_k:uarIaG2b]$],)V)T=O-Z,`1-/`oIJ8g0D.$U%_T4!EYeAT<3BEWi&i+G:np_gp\r_"6(0(u5VFaa%KnEq=oX>6^#pC9FYM+@=)&I\/`?F4gc.P7>&iVe.kH6XJh60q=NHhWj":XgoNDDH"#s!bqle\rUaOWSd?:^(YJl^jo%&I&tib^85;kJ9LUNq/dT2f+#_sh\L;9'YJVeV9JR!Y<:XbVJNDCRsIWPB6cZNg:_8YQF3g^-,+$e&*l!HbQ~> +Gatm=gN)%,&:N/3n?'f+KFf9B9Abo^b.*XYg.$L*q>cYNKpj2#'(Vl+hrT8PJ[XA(A.fh($1+6HB6SoSgodfgX7%S(gq_gnX4S`$'*J@6lgs95[3(RIWMHk)rP&-Sh=L2/="RF!n"lQ"\#Zo\D@(jip(,\t3L`R?U^/-M1V>K;;3&'8u1id-0R`$8#1dW<8QC?R8nAbFbE0I_ApkOL`hN<`X.0^Rac<1N0sopk-&Te3`7S>5(CQ.LgQX4F_b$##tA"F7#?@G8o=?X^>"Q-jI;Ic!MbtEZE!(Q=PREf@=t$O4qXVII"oH?7(ZFA/setGjEaSme#0SKak\psSEe*sIe^rrVrsfo&:`U_jb.ro_8susI`G!sE#s);]q@0O+\.$FR4?qCeC[A\"$?ns$\D4Z!@+,T$UQPV%6Y>Xh6'u+g?_e7U'\QT0pRYb*\e`N@e,ja+q(c2W$HgHPn-DSBpkK[jj@&)A<*$1MU\F(Ym$XV.de>P:sAVh/;Hb4aDuiGrr"+Y1ITp_gsV<2ml,=h9TKjRGIDm/N0!G"K2:=%s1f_85Mm&uo7%0en[uYP)?Pb&@Ps,N41BMO^'0].+B<`e#>N]$E56Tfn0/*B9&+Imb`oF:\ZSnOA#5nAL3>0!i:D="]7fg)M.iQf9ND?.\rbX*"H(e\Kb%(^iKi#?;%:G1r`%4JT8D7\F5W,MX5pOK2=+^Q@#+8#<+V,9#>^?MJl,5usJcLA7cN#6;YMg_m:'=F7.7$[,d(F?5&1[mbS'^bD!e<6dK3g6IUbTb_[q:+"t"j)A``*)5$>^ldR"EsOC9$#m3tbkN`#Lp:8>p=NY(J;q4_3Gn>ol/\2r(4NS$qG]=XPQ_<=90gPiR>\MugT0?r]Ff%`'kX,Xdg!R@qY;%4a7E_WP5F?Da7EOK1-T4hgu*&lO-la\a%]q/(6Xa!(^[)S8=RWrK&kt&1%>=g_64O7]H]kR*Q02bqCG@;QUNJRAYAU[%Xj$Z3cp))PF1K'$1E@%FM6PJmQr"%5R\XO!*I5no$SaEb#VU73/-k,TA\'/9/3s2Ylr52/Mp*W%Y<,5V48ek\-Q"rBeJ&QV!KDUdc6C3@<@9J&dPgrrOW35'92_r+KRk,/?8@MZ!Y1;3gZX(;g56,E]2S^`bYa"1WR4;eR\R)/emgu2a5M-Dj4Ssp1R.cB9ZXal4F`GD#FX_'E`!U,jd1E-(.!+nSQo8IIaiPo]-B$i:T*ZRB@:#WahFCAm$)*h4(-Vsp@7&RM]5EbSV/.Jjm5p&k4TD_3MgtY(+9j#]&t(IS@Vp-+=et2;Zb*&Z_(AHMT17XSH[<$A5Di'Hfh,_@]Uf3Vn&cX-RMJudR)f_#@To3n?.mIdhI.F\_gjk"K`@na`jFkMmsFP*[lsDX-4b2\cj5c8K7pC?NH0cCL_HL1ah>-7cib;Rl1]m$>T"s3tU50KY/*3*$KU&SSZX_SX[m?>VGXfd!6?! endstream endobj 78 0 obj @@ -502,10 +502,10 @@ endobj >> endobj 89 0 obj -<< /Length 1898 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1918 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -GatU4m;CZ:'`IKud(^lWX\,m0fg&U]:$Tr,lX[>'$ttNKQ=sL$7!bT_,^oMpI>+"#RC/3iEo?^c/A?4qg\S?RsADP*_`]F"/f>a^lN9].g++h352fGX=n3*H>\_T9$1:1;d.Om-tddb#"1X=j@MXY3DK^'B(ELb,OpPZ7oZ-7q,T[L4Nin^8D$\j?FtQ+'EuhDGemkcGZB>k34n9d&j;YVIC7Y@G5)p#Cqo)l.-TKt/XNR5=MQgdd=K_6'^-hhd9_h9h.;fcEajYd0p5CUc92bA$O'+"1dO%t=;X"4oK[FpTGbc@$nl448&fKqs<1`A,0OKF)&WKBb=sV9@FVErt*1Tj8KDaKs]rJg%%<,>d>4PB%U-_VS.5U-6.U79`a+i2C1V_'(EhceD$bI_gY9oAS=F<'?"n2%QXZ2i0JAB`\N0qBRa2^J6sNslU4oY9mk+X.QUDr6Hj+!bB;9a<0RPqJW,\!LW8K\)._Qn?'K.Ab.+TLqOJnaK+^g3qS_tB3[@FG-a.Ln[8]aWg4FZnZtk,WViK5<1!H,WfC_q^t0r&M.$=p9]U-'_NH)^=-=85-h(3`nBPCCfT6gJo/'&k;Rm<\ldj>]Xdt-j+l/WIeU0r*-lbk6VMuunct?j.!g6Z(a55.LFOF6k:r9[/HZJInI^L2V\Tsoc\Ed?g41$MU%JAimE.9q&SRZ]ka`^;+ZYVcD>Lg*([&EiVbgobQ]db@,Eo-T;KNa-WA)+0H_FTV[adY:5c[`M4/M.)";O"iX\qC#:bfeZ;o09:d.(E]aR/rMmis6Pt5pTjNUXJQo$o#oo4G0IKAXTdd.'b-(fIk)HsYHG1m+[R=j15q)=9T\Gu$@K?eg0b2SY'(7Xa\ZAE%56]<883ua'4cR14A#A';#c5B2bi<5Dk\F,7N)?2S1EFrp5k`7HqMcZ:pJ@.0\'pqR2%%m^VY-e.J$h@"aK/]fOtJVmDUk\%\LR/"oCVbs:E=.0aA*.q5*1g(YV^6X/TO;@gl^&S]mu?Vld`BZI:US!X./p2Xs8NSq:8H.acCiMEUY0G9kA#!V]t@LM(RM0PH1j2gAgi4[mcM$XF9T&3Sj2.b:/)G9RLZI;.;)$:OJ`rq0V>2o_MO6;&.mt,l+fF)Ud@`d=+AMoABi<-8EX*\8Ph`>m@$IirE'N(_3FnA#p:[imS*>f5C',1WhN!<7<+\Of4;imc="l:s(E&lfSV;dD/r$Vg';.'JZCR:'B4GeZa@Rb@F6>cXn`MG-NKF85Zr_,eUqnHs?#uPf\T&A*jVnD!GOjG1,8'8n$l!0brFa/KMh#X,EAVisTh`#W&RbE49.G>i\GG*?R#$0qS)s,>5/#G\g#`#*:$R_Ngp@/tsVG<,8d@s@IcSP/>m)b*aTP-\mFe`0tc.5QLTcF?^FY8o!6$\m1D(ftd0'pBAg&Tfpq=ZX]:u@G,\tA;]F1\:,ni#-l695V'SZj%9p1t@D;]ciqgR@EsPUF(kAPqEn,1I!*3V"/&,"LsRX_NC=X2ZZg +GatU4>Ar7S'Roe[d+]2K<[Cn3AY:Q8-?\K'FgB[.#1Q(,9=-9M,!AfKV8%IL\+!4g&oU.!7&7c=O5IM>j(e't2>DN+)a!in4IB3S&EDn3k;285Z!kd`Eg8h"Bb9k[:sTq('Z)A)`>R)M)1j>[q=RE=W>O2N+q*`@R'jBMF"nhc?t4D$ZdHgU7[;<0j)j#N%]do?E4k3SB]EVS<"m@1BW[Dg12C:Xir7mYbiVHgF\@fb=D5mL"kOe\8-KR5]lFI,mkbD?Z0`CNVK3VPpL/`\0Pcii%kA)>,&TEgXB*6g1/V0F_Q=pbIoZn+2Nkqjq*k7kfT.3oKF.ujX:-Md_^5H%oK>.RBZ1s7\W#22M,!BI#?<%qi^DZhP;d\kk=O>(mCSS/OP:_=bT9X+kb9L3s#6CPHm]&nI8,K-)*B$_*@rN-*K^K@,oBi:bIL#_eH%R5SM+:I*Y6,nkC(Xks=A4+6&qT'3\62q4nW>s\&^ET+ZXm_BF112ISDF,5j^N@^I<55=or$nLIeU0r*'*?V+f7Iqpg]p..!g6X(a56YKIS+3B+^Ge/HZLO]*Lcd;fdh[k@5K0D*[a[M=ghQC!/@k&SRZ]k^sl!+?>N'D0f9'Me3`dRP+DuJR8g#\`G**H4P)QjY46DP+)Zaj[r=&&!r@scr.sCT.-(K`PX!(.)";O"iX\qD;Nd_eZ>0s9:d1)E\mk#rMIQo65Y,jTjNUXJm0UE!?;hi0IKAXTa@l\MQ[#^k)HsYHG2032FM9[5q$dcT\GDi@0&+90b2SY`46c"].6$II*cQkZE1,+'K!EG3PdBB2#JtdW>:7JO]L8BR?K4uX'uND]h2>hC>#otZ9+@)d2Q.l#F3#/j6]rVX^s)$=pHRK>._+pD!_\XBiD?SQ]fLWb<.<(;0U?+?qGE+`mZ0r$TYl'KFOu3>,'%YMK$8;rgGe1>uY+bZ@$BHD]6LFob9b!Zl_:V&udMSs2_Ib;Tk?ckY$KSoW@b.28Aq!\65usQch/]FuOIDPU,_O8MVjP#48q`O16B51JObq7-eg;g/,F5g_7-^9:@,`PUZtU3)q&PhaT^jHh%C"2`=,5X-t9:,cBTuE*\GkA6.aX_W-73FG2PtOY#FI3g,PrKliHm+0Ab2-`%g/_(H!4;Ig*JLQC_6UcP*PK)W+@co<4N_qo5DB[VE2qW*brCUA?q+d4eWhS^[.lB9?+lpaE;2X.:L-aHVC\E1u6(m)qqAs-F$K+c7o)1RqW_[5\!a$2m.GUl:P$f%j!&%SndQ2;l#P'Sp;rI5c5+^iYK=e`I^O"\C]CN/8!lQntl5W")NL4dh\dM=29of>it.F_[_2k"XQXR@2T6:JR,X72)]D/)fK.[pmdSQkQ[;%u.C9.rL!Kc#']@L@&,p$':.GCBft@oe"jrqq2`G[p97lY*7,GRCF'[4"=3\sHU9TY!- endstream endobj 90 0 obj @@ -517,10 +517,10 @@ endobj >> endobj 91 0 obj -<< /Length 2410 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 2325 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gat=-D/\/e&H88.+lph0+_F0V=S=ca=OXiSdC!8D@0PeeTIn=K-;,g;fl;N?.*8pcAC>JPU9uD+jP=m$ceVGO*\Lb^>^X)Tc9hPXI5,o%lO8P9rI5C0f7VElOs'B;adq,(*u?T%S.H)l1'4XDRtM:EoTP'k_JNnqqCd!FRA!-*DW!XYSA28a)h:5?+0?%6=(O"09Wjq9S;0$d'RWN)!t+G>DPH4`>fJZI(-LW?Pp4Q"^dIXDl'IOVEWqb(7*68/`ckgee)hOpS+BK45X7iXgI%'*^]Q*!1"pJ[fo2aV(arCdi$p$,fF5uE]?AG3R\C&L@`>YdK*Q!D+TFogZ@j_COq0ZANDR,.EVE9P7DDV;kfQ]%UMTcl@lKR?_M6>+2$a-Pn8>%9p]D40DiL#eU*Zi:$@"T2,RE--TU[C2*.13+i/*uo^(m8=gG/SL#DY$kj='7XOO;p]dL:;@)Eud`?ndm32lRq?^8Si!jf#[F1'$KALmTj0=+:+a&Q29HfVH-lPDpZ?FXKX8TI3O)t'X(ERT9dC.0u=_0*M[J;@_Td@$>g;3R4nC6^E+P:)5Z\p4#XJ:bM9HX;#CdGf<+]M3r/P_=n@p]#YN%(nF\\B-fq;s_)o3dZH1Wj&U@!#S5rI)5j*u-4EGK5]Y;W+[)A-r/*N/Bs]sU0X75DEB?9^@nD064*.\&e3BOLX%SHmA9*eZQE.(PQ&SNXCBm\-.2ak)HdGf0*d19fApfN&tM4ftao"fcCoI7bQ`s+!3&#oaPp!8>^2\?;IiG%h4El+fHPX8DA]e?N!EXfVX/slk(H?ZsE1LjZ9r'bEZjIfip[.>AXL2@V28B!tlYg^fl%@A%qPT@%[19WO!1ogB5tG@ONa;W.I+Y\b$XgQcp4cQGPB',_)I*[:IABVh22DWTV;og3an%7WZkjd\!UBqX,dt=EF_jZ+@XrncMD@7$uK*%^qk\nuFAd*\e-Q$Q:8i'Y.\:Q;!UC>h;HDH9bTE'pJS)+H/R"@koQj*o+(?]cX-9]s-GGN%[SB2M3%3)65j;3Cia.T/CuK`W3mfe2M"fTcQJ*$5l=bUb(pOjLcrO\OS=4eHl=$G04g"[I7F]7>;nC3g.+W$Z+W[_^NZLJWe^ao_.=Imt%s/k!Kk[17E&QW.<]lGJ\jtQ##3S._p1-MR9jU6"_8R\:Lqu4'@C@2a5ufQtdAK8dbU(lPTVHFimH/*t6YFmKZP^5g.fMfs"$G&3UdR;ZXl__J05+gs%ig+Gn*e*N%9kX;b6EYLmC6`6gfahAJcZrn[o`X>Sn`E0!XkdqEkntKoRRTe8%>f&J#`SD%7*2g+pAU(ObA=O\]X%*BnQ?A8(e]Kf9O_,RULog?N&H_c2NqT^/-cT%ahsk=uRe68fi3n-U#)0i(o:6Jb!U\I0BYJ@"La"U7L)smD_lWqXhLHK;Cn,n+%N)\@D.bG,L:Lfh.T:sm/TE'N:6A6h!>O$g,kMp5bL-@-"'nleooF,Xh\%_?#nbLS(>[Z%i/?YAH~> +Gat=-D/\/e&H88.+lph0+]0OgZK--FYU4L^U2.@fHNE9&TIn=K.SDBcfl;N?.*8pc.+3*nU9Q,'jP=m$ceVGO*mS(US:*EhS[nUsl>5OlShh>re_`'\YHO^Pmfq1TiRF9erI4J"aU)AgWh8_PBB.)'"*NoQ47enDT).V3mE?ttLL01,/=h8ChGq`RUNq1M>R/MW(JJr&E^@i\#%![*c""Ea1*,PZ[7G1lca=h)GC$K"cs#L[/1_^YDi;nXUAiGk$=ijS]&p%5Q:*_?J'CZQT7F]LOB"eC@B.TstmDa?XV;p^Kp9.4]aT-ma\A95<_?(c\Yt38[>K^V(cbVl&C'dt(^gL(pbNgc>$YTkVbk[D;&q^F$&g74/1F_9T.o*8Mf/H%T7BX+T!\*tog-A_g=rh&##9(4:g_;YW>-9=DT80=LXV(j6jf^"@X:>D)W3D]dPmoQ3fE`hAa[=66Lpg(g#15unNW1M36*6h8\_&UH0I#G73_lB0C28B&atgOE4:$"=0=e^J4*t_WVabtA8&LA^c>1=]S:/piHVA$D&9/0n:0qhRArqaF.LF;C^)+dd7l%R8m(QNiI?k0hJQM4\gp_iOG_.C@-SpnCohVStbg[I>K.aTZCkK#1K,M)P!"dV"VAU/\Wc%(@9u'YBP#i@/$*&e0#CNeRNO:+"RPSW@%;LWmNYjSl=EZUW_rAoh3umPGKB3Hr&-n4@_H,]2MD]ir:i$\o)T%07*U(VaO)C9;oWOlM6DU6^$XR#>ZR`PU>hdEXqAJ"%_]TRj")Sm:#XALCd\@]OSX0HU]WXu!%2754W9+XY=eS(qgl]lN>>Qr./`\I:A#Mrt5W*":OO9*mA)gM6qb#Ri*9BY2cG7jMX]KW=A0\#+8mMN\pZQY3DfOHpU2#E)#%onFM5m]X&B5S=oE_$\am51p?*5r;JseK%&-7B93+G_KB97ZgqQg1:_!Mo2;/*4JcDish87PT&Bhn3Zg:1N]m/3]Y66moOGbkOZXGNfk;qgWmZru\;$tEW![21Lc4su-eSaNb)1-f/FDD!^k[peV;ECrBF*s@q;D8W(Qu,?1:c/N>oP)Y\1JX2fki`ss]3/I:cl!S6,Xq-iZd5RtJ7gnXk@j%feVk:%"\#NcJHJa;rB2"1+_tP5fq>SJk/[/Ph8_:9_E@I1mFaIBI$Gf=Y@SQVB]P3OTS4q:"5p.s96apup*-';kY%HgqlF!V.ngtB0#h2S:?'?CQH=^0X*Yo?1pMgB7PeHX:l#5*s2O$Yd^G9VMZF1dq0"-%`4FU.$K5o`APqlLr/mV!Ft8Z:/5pSiPJj_VYEi\4+GmKb#O)[2fllpa'4C'OaMApdrtEjIh[C@@,Imi,/eEh?&X95Jbt-='(+2s7C>M49~> endstream endobj 92 0 obj @@ -532,10 +532,10 @@ endobj >> endobj 93 0 obj -<< /Length 1678 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1787 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gatm`th!5dA+:[ooNZDRYV1I;&IB99^[NP$D:_jR50pXDhj2N<9;L&sFN=R5nnl%Xk`gr4H52]3sJ"I_REH8uNP\+oE(+rk.k*7XQ,#NUkYYh\T?ID@dDrX5@7h*ol`tPqV@*M8Bep`f1!H+Vik6o_uGCMFOFJh)pgDhNAD)?2SuO.PpAXMq3jX@]R]Y5M7oodZClEi4\P4n;aMT3g0Ip8iN\>#[s[YGu5Rq7@kWj%D(V9TIp.q=.f-te1J6c,`DF@E1M@F[Ut9&_+n^8Lu=`q9:]-F)_k)peKPO"]@@PVaXp+sdnU#/3OLaCG3?9?X1T$&R"'BN%TP'`QEnX#df2EPG#C4sD;#\>Q!miWU/7gZjC8SRV5Veq]*n;!Wa07k`GlTCI'@H+.eBW@,#/E9]K0WOh$$AkW9Ru,\boj!lkAa$^$DTBZBN&bH)pG9?MP$aS(hbVN]-*bB%PB(&]TK!Ia"pcGOi_O^)7NmM3)60ad-WY,egZT+E+Md&loI;dO*uZX$<--,_rd-),+lP"DsGd,J;\i0tZUFLSD@#acb/B-tW!@&AV'/AlG=T4`T3I"BD:*;U[lrRjEHXWt7%r9EEmdRg<20:t,;\P9J]%O*eN`h`l*dR%V$Xqo(Dh!(q@Db;N4d$i@o/;_rXNRihZRJ]tQa#m:cmd[f`"//mU)[IO^i=mr#@h/_qiAf1,O6tZWeRsU.-)Z8Q<`M-IE"[4]P9/1^h07Lpbj6LfAqH]qr"KQQ1Ea30h?$^VnLZVY:Z80]oE>?9j,7E,,A%&_:DeredEVklk.>Ao[j.$\eMnO@>S%ee,/TC_Q:'a&L_:J\\_W('j>b7U-U*B-Z-m;dITi`4C6+-(np.Ph:\*WOeho2`m4Y7bYJY/#hh2fc#GGM]1$5npW[#UW8.=V/#fYQ~> +Gatm!@U=R1Li(QcFa)/QcQ.)@>5Ys8r*1pg"+OYn&LGrsI32cYTg(3d+,-4obZ/]Kr9LG5RlKe)`#G4qpG`"$]13E\niLsc/N>^"otpN,aRNbEA3X;*Bih8j_k*nYgM=-%&@Ag`Y3fb@M\_US7s`0jmLqd/I0>(Z49(`lJ3?T4Xd\u)*3=\pB=$"L_HP3&N8$tRB8\a2Qb]VVXOt1E75lSL8W;222=!8D#ou.3<*o!P9h?533ET2:S>'\u%0'&IRF+i"h*M[Wbn=SV=^W&h@S1H0G[;6qr'WO]";+'J*.lOJ\KZf/SXN@f7NlmprU)D;hZ]!+a/LtWrQ@F?35,Xh?_lpT`F07T_33&]b4+VGYLB3!E;(B9p^O-HSHf%U?Vpq(*K\H^`Lmcg$csJD&`?EGDdFT/=0/`Xe+2TauUrS8=Skj3hrRVo0Ma);VNeo!QusIsd+]AV+DjXphHOB3[AqAiV.C8%LhnL2fg3mqeDUFLu.F(]K6f$<--@_rd-)+J642l'=6^B1XW@q/babO/]Q?pM-#8Xt)sC]N1F[E=ql:RmC`o/Y9X"h=TSD_PO\S\(C1csU)fNgH`q>=3=L,;)f]dBecIX]?Cs)d;"WkJSJ69GP.Yj,sn*Wmto.-q_B#?5CTJ2]udp:$os0L*o=aS5VZm6PZI5:1DL^dUQI^gBQDM>\\.hK>Ad^<"gZ9cu9r3"]YL#/UJHY^eJP00:3m+oqjm42q)/R?P(QNm>MTf^8l!oh%T%L4Ur8/@K+XWBV*(4T4M_W\EB$jpZAh[jj5(d_D5P_d?GQ/_%&ReU]S9p@>[T3UKXFR8>.b(CY,M=WS8,)aDZqXG=gl1^.%-;)[:]*NtDd9#icS3;*cCPm#(alpb0I@7@XY'L,*IVmq%WIF323!7U4+X?#OOu:8Qh$aA$D7f%GT\F(S)&*_DT_Bp$`-3sORu_[#S2;47&_HfoSFm>%^K#b:S'4DNofC#-@j9e\]URejo9=591V^YfT,:G>fjjb/E+$%O+V+0I:>G;AU(('GliI#\U+EGB3H/r)OcETZ8RX5cSqV$>E@5OJ[`Nj5S:K#1NI\PD2dWt/6\QQ,OAN$H(Tm7@X6` endstream endobj 94 0 obj @@ -547,10 +547,10 @@ endobj >> endobj 95 0 obj -<< /Length 1563 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1558 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -GauHL>Ar7S'Roe[d+a^,<^g3D@2Q5Uo8mDh3lK99ZNisoCne6!M,Z,+oqO,t%jfVCemKmER$VmkGg=>S?ERnTX_.UWOL&!fJ"J$YlT&AjWkX#0r14-$m)DdhSbq)IZccEgJ%#h+K[n3pT6[Q'Vu@j;P74Z7HG6`>3a^0uN#((mPN(Acj&XjdI/]$F>Wtf,melIR4q#Yj/u5/gsi347f%+s6fg%k5:5I-5eIf!`IDh\0_tL[nfL?MKQ1qMFu1[$JPJs=Q1R0n2sbRs">d/?mQmV-nKj@9TWmp;Y"R<_glZnPQosZni!#.Au98R'TLk'aU3W-:N$O@2F5uXkCSoae6I5;(bhVXjn57TZkBB0Tq:BsOM8+I(l76GGE>A2_o%d;7F^T=p=e,\G+fnc7$3!MkSI9)jc+>O+Col.=<`;he8_)#Lc5A-7C<[FUneF_g2,W8-9=+:aFAmB\;\ro6KgJ&tZ(q^"1?ZTrF,>^hF^4O=_VtH@AEd0iY*5c0:/\UD[dl.kZ'PYFaBL*njTTeX$#GJgpY:I2bW).qI'D%?UB.SMs4a=G(LG%'J#"@r(m_(pS@=']^hR+%]!]@>?F)$e`MAO)(5QYrsltKE7'E-)u!U]?uW$U!08]"(E"/#rmd`jb&@$8BEJLO89_84Q`p*.b;,Z#fBaU?)?#Q+gH7A(lD1ZbW&$PHkM&YqL`e,QtD\Ks[=`M^H#!R!EDID`c.^BJr4C'upnRqaJi5:_CRIp+'lF?Z1L"Fo#)B!!m&(%R&8^IV73HIXhu7qca]4D(%u-:^+MUR<&qpTbZZ0kMVplGC05.nN/\rS.`g;Z+D$cklHa#bl?j0Z5'RB:e1G]c2#O7GI.2D,EN>i=?hMj8t69.?rqWAC09C@I[EM'FiPCnU=N*gR/+/_mSqei^;:])triY]&?a67S`[KH5fdr#Y3Kt]24C%ep,2sUC&eATNuHR^OTIf\9@`oIBbYZk"iG#J7Rdt?/,Cksh@OG36@)t!KK?5iogCj]N,_-HS*",8DJ:?n6jbOYqa55j>0Vf&[hC/C-'Xr6?^X-EhG;<;r(:VD?KUlTZfnY;6Jk4n[7^I\?hQKkP!;R`i&m)6%kWo?Q,2$bS#Mne[Z7^j.4-^[:FG0^)c;d,VgF(9=%^(3$CSpp?cqW]>Hmn*CIfKAo9p5p0%;:*&hWr"eih?WZNq]M@"3UtoblFRtQ?f8.8qVl$C["cP9Z&>4A;s/Nb!q4]9B>l;>l9h#K^lNc0.p+8Zh^RouaRcIsf)"_'oo#H_hD`iA($*pDR@;BbcfRLU/_~> +GauHLgMZ%0&:O:SkcIDg.jB*hM?;%??"D=e>K!"t9ck4/ZAH_u.oNqEf9_Y:CFG=*dg!c8$WGOpc5b+LNd.t%rN_sl4[[LerV\cM4kFbL-rU'M@JbBmqN77,20BsPJ'>(Pr;,M!F:_J/b@9UVDWCuHEoVO1>MT.*7r,qcF`HinEq1^rfTgSmE.jei^!O5/ZDh87s/%CL`Ab*l<\,7O-JXMJ-r.4d/S09Vbh_Ba9;4ife+Te\p4[ookb;^Hp^o/`fBnE>FSa;J*J=2;&u^k>]JIAT#lm8sLuOp]E^UG]M'$8P;SW148HC'9d4gaB'?:'-3l9G)qHn/n"H.hDMA64m.EKM>K*tfaI5o05SpP\R8=c1&rFS*L!OF@<;*fXHa!SJ5,;-R[!a32q/9Z#RQ<9M/#s@!QN_R[(ugJsTYpa\%.mcgOF,ek+MWQ]dR1e6I57)M5nPi'KY"SjP%5-F'&sT::HZjV)oja!*FF+,peB>PM4)H(Z&V%kh,a%+$`_''Q[M49:j!WB1NTlUHhHZO&`-(A8,:$Y]dl?(nhW(DAS,@mMk@RWe%3E#!ee[Za=60R*c<^Yr).,7pS[It>_3B?c1J-EQ)I0o]W6Jh=\#WlHoKm"^4$e[-Tb4]6>^+b-HUgJPfRdq`^\Vk=C:B&c6^o=CgRRL8/c2)1`5^;o5gSHkJhFD->MDrSQ,PFXYR4hMh2?LM)*56a!Pe8oAhHV,*ir]gL(Mu7iu(5Dh-%mg*)e7qQ4E0@Ftb5f$T-/!U55VPc<\%i]U:uGaG8UHT^6kTb3hrLV3li[9_\1m-f]1fbQfn)QC;?Z)Vlh#\nD!jjI;"8h_lG2ip]"2J1`npj0V7h+E=p'^p`@m+B-nlk),T?5Vh^&!/&MS!sQDdV5V#EfG&`'Lr.6/SfPO6cH%(8LC0SK6jQntP(/8Ijem_!Q+%qW&m4s5;U1a@kiQtFh&L/+]mG$`U3"^?RUqFqKi@C.1C-6Br*-%_CiY#aQ,2sh8W<"Z'!P%@Uk:";uqJ@qF`'Vs/"l,1j9NgJN-kMe[4%m("4qEB2BBmj5MEIcka0;&#^q8<;ILQBR?BQ$E+.Euajf"u)KFgHBtfUHu47r%%+TflBjZ0-]3Y[-gp[b73"9"QL#jOqB76o@@eplL4'Q8Q8LmQLmZfW4O:ZN8D+CDnnn1tIImFt66Uf04,cKA+0:n`Z?;:;.3Y\\Lu"#*W;QHLQHb40DUlMT;gg0S%+UZt^^1)T>LQ"EpJXaS>QTp\!^)6E,`5q91eT2BD#9gT.6t,;V;mn?riT2TNbWNZ0D__7sasu;U#(AX,IJb~> endstream endobj 96 0 obj @@ -562,10 +562,10 @@ endobj >> endobj 97 0 obj -<< /Length 1451 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1417 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gatm;D/\/e&H;*)Tl3SSKHVdA01->E:?s)kg1H2j!LpQLZ"]\p/3/rb35^4C8BEcN.b/?(&30BSGRpE.hAoD0n_j@jn1Z!$6@V0-15p/`a0GUc1%Y:,d0*;^#"f$mK:`Cd(C^WV&I$A(7P#Z]58hcP\?WpINs#T``g"Fj`_eEr"hu'P-tUF'Tg:`>`3_(->!ZBg?Ii/=Q2Ou(_@#m4!C;Tj#$,KSR`e#5$OBsUok`_-YPE2-HSGGub;BW(eAJ\#9(fbpT4GWg`)g_#W_/Q\!*e'8/.-iu$UA3B,j-gg5]Ss`PHOZ0*,cg+7/,Qi9Ag$#(T#Pr=&u`.+:Yj$Y?.(.amf[r8.L6t+1]T)Mk2?=@OAMbi,+?Tk#T.K9EbjpUJS,.'P1tD5@,b4j7(.):Q0-2Ju/HP/rP%2dPM&bdO`@G@(mjPbW!FB)?adeoKU"a&@ChW79XnK*tc@b]/^fVJSlo2s4DC1c#c9!KXR+$7$/cT(()>I4#o0@dM05J3eJ3cm_<`)\2&r7-=Mj$KKVW*/s$(5Xe7?Uq[")hb^DD:OP3@p']//8`YZIbWQ8Br@N,Q/+:XF8;RSE1#b9Wf,X"W"bgR*4l^-l2Ig_JeR?%=+?BjO7_kZX$8@aZ$X]>`V(1LtFNPiUmNYoC#CPRj3@5=iUXmYe,++S%k4iV/j0BrNhu*SSJR7EWmRY2%p>Vbb_=)p#fd7Vr^88ohnP1%VM_sZfg.h6t3?H,Qeo@?#mo^\sVHh3"omTnTe#VmtW!Ti93k?@_l,b*oV(82cHk1+>/.T-W=jQp,/DB`O>KtDM2RZb<6YlM+?+&b?+:M3U^+Ma5RhmQ+O7b=.ShBe,R;ip@5`d3u@]rm4Web(CH-chgBf5rq#.;k2uW?YoPiKhg@Z\OY1LJ6_Gk5\o?).a825Xh#0bHr$Joo[If,FPDI'L?cGnXZbWqf\r5`?\UIS"Z##FX8Xhi?N*(pG**[,9UpU8[?6e?noD31Q;Hh=9?Z>l' +Gatm;D/\/e&H;*)Tl3SSKHVdB01-=ZC$$U,2Pc8c&">M.Z"TW*/@cIc35^2m.EO?+Rac.Z&1#PlFO**o]K;^gAs40!c)0i;pSlN\H8:p%2Yt?Xk,5Y_X3mX@5!KBp0.TR+h&Gk)%R4r*;/*7+uE&DF-?^L&A12BF.Zdl@]<*94*Xmoq)LkcrsIX\#W047%c#Q(iVoX$5USe@90d@3!!6fb:G>IGKKg/X4=o^U]'c.2aa$t^aiaVU")jY_sY/?'hWHO91bKi,AoDg)Qq;uA&O+"p&3g(,5XO-j^gO!]kc5d,e0LVLP2g;1ib7I2uN)8b5Q]pQe?$/'Zd0f7.-78d0S<).4:2t!0[ph@et"5t"5?:q(X,ea7n#&2mgm6>9Z[Q!*hk>NE$OTAqEI>]97Y]gj*qZ!.[FWL)]0'7(fX3C%9=FC$0"HV(B)6^:0$^>%C0C5;m5\&2]pe'54d+sD/%#jd,!2M_A9-#O!4i*qbLr7e3hFc7q'I)B8X.$ThOeZ&UV&(a2oQl1rA*\E;nu:E!8/p_rXu=`d/CN1X$sSI@_5YKOi&2SmeQc7S!%GE4:WiSYngLo$s`cJAL?`NA1/)>^E:2]P%-#aM1sTtI71lA^>5*Ls'[Dn/S5ut1l`th=HBJ':MM5bVs,g+V^V4-R*&XTlupio!5fksq-bQb4u9Z,3s~> endstream endobj 98 0 obj @@ -577,10 +577,10 @@ endobj >> endobj 99 0 obj -<< /Length 1722 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1755 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gb"/'>Ar7S(k).^&G"6P86"Ck"%.XISVIX,OJ,ufQ9E;%'bcd"LSA:*^ODDXR>3QZ-L9$6@45$@P.o]0q$o(HkE@"MPGa7Q4j(M]-WA'/X=/tes$><8^'T5Fp+/t?`T5XmqcA:HFr"8a-f<.+M:5Wgnt0^.:=>MaSfKhB2.'M$?d8sb?!0*mlf_6.SPZ(=-O&=g>!5G;;1j0DLUjN.ba7hm^,Q?HXI\mH.D5<6k`V#%Tc8lUAY&?Bb"<&5glm6qJbSOm"^T`\`_l7E!IF&iXAcBl'mQ"tgVA1!7O!2S5irr93/m42$Pcfg&a]^BY4@R,$&a^bY(p>20`Pmk#PE.8aEUraRLJNe2N3ots*Rkj*Xf]!'uPLH6KS5^@g>7e%cA1ZE;!@CT^%Wjh]!=-sDW!NtFgAOZ)^.RMZU`ZC7X3k:-1P!-RG?UAcEa2NIU,RgLK>YUW#f@[ERX<>'hjWNu#Q#=DI*Hk]BjYItOl/@)fe)"I9Tm@8.5+FJ]3jgjB9ZT_oeER>,omPL8Yr^d]L^TV@EZ/WS"+5l2"UBFW4,O_8!^!"^\8ul_!qC\MM050=6@*+n/.Bd]>C((?ZBo>0*N*6(u=UUbOg[m062'[W8ue^UE3DE5!6-otEc+[I$7W3it(cX31C&XRINh4hCl6.;qO>/mCgLX&j"3VI3:3J=8W)^:!oVR]&U*,K*B84&r+QWP#[Q1iDl*G_ieRum2Kep#mIk,5>&bGbiIad]-F.0N:;$dCAM%lS]4OM3D"9$,K^<*SQ9F7+tJBjC5_\\*XaB_KkHia<,"=4>N*a7r)"*T/0f:SG,e9))(:\q(Np-(]kb.sAn$B/4QC41^.6!u3\P9[U/K'>:r-;_kq(0SmVm3SuQ2Ze@W7AD`W/QJPV%p(\Kmss*#T*_]4e'4c=oblG=l0AKKUZbm'X]ZP6q&VfoHB^e;HKM/.0VH*)Q/;EI;J0DW9uOYHMm[_;S&if')A1Shn:;DE7H/N#Up+!Sl*O-R4a_+uF(H*)f7=P@+)KVJSFqPlp^/#jD?u?5b]2#gsE9tN$K+K]`_pFuETd;W)Y30uB5-X^Oe&Q#meMq7^gC%:Enf0#TUP&&Z"+[NpIq",a*\Q0Y-Smc`H+TBr@+H>o\j7:IL,#YR7FcBE,54%!R,8\~> +Gb"/'>Ar7S'Roe[&H'rZL_WM4bqB1QZlUuu?'_MF__MY+7+oL(dNKoDp?P4?Q?=U>Y-SRc(ks5g.?WfanN.hlo.Cr0Ldj$BgK9?Jmmf1WZjbjd`W*)Bs.4J\b]F8JN5b"YdCWIU^R]_+m>*\u2R8cOQM>)3[M@@d4id1Hf8'dof;n-7B>cd,jP#t\NO:8L(Pqh'EeXA+AiQ2jR[G%)79o+)@c/BH3ER)]Zld(tkbX/X@"Vc)^DYE0_rR[Ndlf%5=E.+lb(!j07*M2$q"4)no_[I2Vl(&t,#`?o%S[0H!%uY/,d_/3_`NZRbWm4s-&/DP5DUFCO3QYh7$cq,SZW)BWJUjgC+qBY-&0Jd_K26'Hm-Lg(@#unca:9*-(cBr%AjjK8O?q!_?l%3W&Oci+WHlO&P5hLn(nX7fu"ceO]Rs$$0DRK?n$a3>-,946*g*TJARf/ApAtqm'X3G'u'chkZG"mm>WrW,hg8reTa@d)J_t(,RZJHKT5s*7^Gd#SI0rkm%m!Wj-F!af?&KXaS'+d`Hbe:Qg>]e4T.+0H]%*A1"".l&EKq$!`7OP.#6n0'M]Yo0.DN9KnPXPRTWf\IlYq&2t_MXGu'Va6SB5iHpT?X&^Q[g&%iF0J+iAkVn%*S8:GL]I2tI/PtElR$BY1nsI81/hbkI'PA:mLa:p3!gQuCFM[qi@+#n[JW*)]i8D-a0V$<#?(07kjDY2r:.#j@[=4N:/:3B/9a7dQ^n(YDRck*bM%H&ja[\ZBYHM*"q4ETirm%:dK5aI`.D"Q7^meMSEGtLrGN&`VH>%g>1=M8XSkJIp&_fJ'VNmGbF506r*I?+s+/eZZD\^l&e4j5;enF`p7h6SlhTT/8ka)0IUcJ+qlMCn+Q.An]eleEO!:W?!JNH(Z2Rl"9~> endstream endobj 100 0 obj @@ -592,10 +592,10 @@ endobj >> endobj 101 0 obj -<< /Length 1895 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1797 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -GatU4gMZ%0&:O:SkcG0V0Y1VK@"[:2=_*X1Bk+L\lRbBVPXAC_'2$ED?XH^:bb7_afdq_#-;DdU)4nC#T4X9oB9UAmkH)Ykk=Oe[f88Nir!anHq'6;pPX^5AM6iTI1&5p1K,81A#KooH,00;o2m[nkG.V#Lj#N^#b,pee@Q/C@V=XBD\lt5_92[VAfK&I`ECVP-&73eBe7u.s-Yi.dC>)KbW>V#>V%de]U4*1(R2B:43E%`[<:$P7W_`eOjg6.$%BmaRDpI^mfYAUsiF(RGjpbV)"m/akOZ).(c,pdGF2CMV"EOt!4;20+q]gP5,cm;nJc#po`=dcs)$e7KO?502i*3rD7XeEN7n.dUCU`^X9AnOW%LXO$,!@j6\Ao')]2=k=NrW_sOiG'qAe&&WTUi)+1@TePG!cFkjQq7aC^?.iAj9G+j]3sHhD9U!FWQGr9GrCL_5X$f?XT<[\fBBdJq0VI6d.M_"\`.:eOI-'M^YotH"#o:t'_VCV'#:?:nQQuLNjpJGB6:A7E`,YQX%bd96T8RQV7-.eaYDfm6+Nh.e_Q>C;FIjtQT26NMN@;s:t2>!^d7`N.[:02W$hXCT'PHd`/fqAmt/?GZaI\[$R*(1udSVc>BL.fjn2Cg"miX,R/p7,FdZm11_/A6@Ai>1mpb6#0"bGi1*\CeN.jJ?MBJJ5O(D]e:hMGUZb&epGAarD%9PkTXrL3SugjeVmS9CL9D[$m1F-1ST*oTrb'7%#hS0()Jjm=o\YD01FOo>dE?]4-b)8B!?NMS:".c1YHTc?*GNq)K:NP%+`O3(TaaYZ.)&FZ32IX^'k&RB`rLOgQ=9]fh%-sZ##>3+f;l:Hj-t"jlbN[P+tRQHna4XqJ9@PDb.9RmRQ.!^&dPLDbF)$:V6e1cSjM3nq.Nf&1VF4pY1cr=X3sfCVfM?pYGXEK'DGYlT1'*r,X%8^/]sPQ;NM/gn`gDXn%co_hiRMVabO8at-Zp\i-nL:L(k(,>O`DRk>-f,_d2XYIj=V@9I)f7C;2j!O@l[I-,c3'C6(KLOq-m"*g5T"r8;j:0UVYn#)&A]Q*FtK],U`G/oH^*tTGsXepmK@^_1pj:+pZ4%13lhPjJ-1cTXe1IEI_#+hAZcB.;$d4Z([Pl%2bi@QeRs387D)M94h58%ASYS7m-.ak@LQ2.X#gBei=Mp;/94mP#*Bd$H\rJ+dl.aadpq2e0DYC%]d+hT1UY)iK;EY#+/jN&\?be_gi-NZ8+M+m&,.#]$p,)'569HZ`-!WaTYAB\?(Vo8]0.TF5)H&a:VmB$N/RZiM^(_sm6#l>#T)jdQ&AjiGCE-;dDM#-2=b$3+7-?*%K~> +GatU4=`<=Y&:XAWcs%15;+04iJcr\W]h"8$Bk(s$em!Zj.@[7G7n9*Af9auq%V=)6mNP22dcAV2_`9pOj*^F`I.BBc`gZjTRREHU)8>RG^TPUA?[*&9IEsW?@OrmV:-P9)?mE)\/AI^##-uo@o42=<].EZ.$tP'>X(Rp9jVma7pi88?ATj]LBM>FI-E*2RG&_LR#$9WDUmR$"[Y)6LOgN-[UIi2p[V57.h"YX.IiGG#QFVW_+[i+$o0\YDeT-a_g;i9U8Bl\3**Q?\L_srdMUo/U`CuE0V%dfXU4*1(_'*9"8(io-UWT[3Y_8mlKMGGakXC&:%0g]i=jslPE=%YUf&3m[aq[V`;Na-HF%]F"#gn5%&\jF?0&HXY8I)D0+,CNS=!KCKLP1[*mN$[@-Ii=\u-)m??el\6s1khDJ:M*LU5[Tk2i@G`%Rn%es-WE-)0MY'Y$O"Kh\X;S1*c(jKq5eE6+-`@9_bejS[+K*=W!g(,NC&t=UU3$%HltaAoVAM:IkS0nXuGU7gA&Gs"_b!u\-Y[K"n;@%OlJQV%1:+tiRqoh6]QP_G=&,AJCrSf>[*-pJN!;kg@rm@'%Slq(tSW@"aQ>"830&,"cBGZoYB;rfg5\ZSu/["FfZ_%#To!>1TYj%Tg_H:3>bC'(8hm].=_JEi1&R'S4COl3gE-\B!?P#hDP'\fF`B>\AQ`p6[-`;+F'LBm,MXgGY03J@r-qH-tPKCM8lhYU7%DBFA][_H5f)O-.U6/cT'JrDXL:SFQA\#Mr[AT?(F:0@QZFDt.pkLI&?@o"&7koLHDUO:`3r,HGONW,Lc%`p:e@&J6E:fuk1bWN"gU[c@2e[>8?q`'$D93,i-iO@d;M\N~> endstream endobj 102 0 obj @@ -607,10 +607,10 @@ endobj >> endobj 103 0 obj -<< /Length 2071 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1981 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gb!#]>Ar7S'Roe[d+_GL;+05G+9U2QM[jI[Xi=\5%:Ca0-74X#7E*B`+!k(@3AP/-D7:6G&lTQkpjN(cL#f;RjR$FIGs\Ttrd?_n3jrOP@As5&62gU/E!&014A.HqIe)gce]A;M(t^HcrH]5]`7<`rdYZHFEqBmIg7Ek2LQ6:)2V&rd1Eg+-=)Kh<"ad&7,%Hu<'=DG#A&75<-J@RfJ!@h<'_KkXp9!_N0@tVN/=2V)K8=m]XRNn&S;:aa@CbZqPjEsP(MKDUa[uaA;LHBhPs;Ci0*;9gWU4m4*&kpDg)_AIb8!FNiG+JV3bVP\qR3-@^]a,Z#d^MO19os:$3L020gps#L44WEX7E)!*/SOA"%NDHR2C>F9O39bA34)KpZXZ]/X$a&XPiZK1Z@rr=^[pg9#YIQ6m"gJ*Hr'h9AfM>i:m(t,F4u$k!_MGA4n)0Eb(jR'p;XfHR9n,m1Z.JerP4DS$as[LWKdi5o[j<5`+oWco+5^8Zus?Jd$SF"GO'.S7KK0HCqGF.T2:':qQE30Ec?\,rfFcq&9#[,V'a9;+r]?;lq^KL/a&Ti,o-H(FWW0H/PCu7Ps)S8=2^:4"]1bULu:&npd"ICY&i_"MNuI.u*eSs)0@rGTG5E3Q_@-H@oWq,iegJgWA6VHj.1q74G&r4+XmT^8)*iD1k+m$jM>&IZ]r]J/8l<5E>Wn2%2?U8/Q$3(LH6ujGJl."Nsi$*6]pBI4iL6.?'kj=^T58ID@=ULfC@&uEed-\^a'"VTkX[`RL`0a%D.[?DD6Zn,LFd'F"_p4t%f6k?,WnNgX*Eum#g'8r9%Ld9e;=Dp\W_s=7CPT)jhfusCDCC_g&rm.rh1CQ:<_.)H!>?.tNO,'U""jYTNMX]2jnX/>+9DCL"Hc3I+AN_#V0U0j.C"AWW_tJ.n:r_@VbMkn8coPO8quF?<:KjMK#>u8Z*E)0cW30K4J)$G[AI\to[$:C61U$85n=lM5`>hj0do^f*>f=`i:Zq%FtgR+Yau6H,su3U9&VJ\T-jdq!d2Y8,DCCbPJ7>OKV3;[m\O=rp:>,[0N6f@BRe$8ki?0>W_PPNBEQp*c!.(p1(]?])e@uE%-Fb*Md,!"8)SDF9R(/Ik@&[+/CA0C+%nAoAM?B?4lL!Z2i^c%D@B.#[qulNdTflk)m=7rn,rK0m[b*Z=I%#;sX[WhrS4GUF`K]=@lB'3qkePQq;**u$&/;*>gep->?Z%/6SGU(H)\dL8rT'a79Q_Z9_#;=$C(N,btkbj..4P/]0@@6*'9b3Nb?oBI7!6!JMW9;9c#=<=,6?97_7,-gD,!--T8p>)1W.ggd679c5:OPJ%+VUTn*V2CioYb7YB3rW2D0?pO~> +Gb!#]fl#h.'Rf^WkcG/[.$C[N*ZtVI98XFO,"7IaTl'm#VJN!4kb4e3q>6?G_F'0c4d0SA0G9a.aieaMmR$I2AFO"_pb_K2\bu>=0_SbtM;q_;%jUcG1($?lj9Y$5%XoG24l5!*N:'b+OWtrnc6O?RbpZA:HtP5j$Ja8AS]T=Uj,B8dc=PAHElMau$f.fu<&ZQu5Lm,3?h>RQA3jMWqL(X;h0RDrpGB(0I3a68`>9F-Pg"6-^b;MAE[%2!r,u:DYe]#[h"fEer7p:C3-N1[07:mA8S0ndM4.`j!grPQ,-32>E6ZKs2l:5.Z+@KIo89Yj7KM3f&.hO]iB)OF8<$2hXg,%mu&O#[D,_m'XXP\Yc(+b7tQQ*ecbe)kj#BM"1(2(<-?-M:rK+VT7Vl>?Ve!p*'":Q3n56kWi#KGh],:5c5bFX!$VpihS-$EVV77!n@R@X*t/s/+4r2[Xp&Ak-bEX".d[*'apnDd/qdug`+IC\s3c<4THGf1Du"f_>hO6r`I,iAA=H;No-@OE:O_PEEIYqsDTY:jD+K\$TT(kB/")qg'Gkf3K5V%>n_o&!!s?H;,F5mfdi0&O;U]'Bmf!Fm4r4qKj,Rn*IB5bqNo9Q&VZ/""iq.B+P9hQ'&MjE8k6!c@OZL/3+s_5ta?8B*]FrDG;6*q!5'?gFm;=YW):8=jr_cq0OE/uE8AT20[al`+Z,VOF)p5(,9SjC)2+*:%9jm.BGBitPXP2&U1@j!tee?dl>CF3OC:EXF/-1JrFb*02Cs9Ip!BP4LQM!-RjaRrr"`G-Qg!P'kn]+`H_$KiJ:"TJFGnm2]GRBXIIP7]%Mi'2a,?O0F;"'m]j[bFsN#n*e:HS"[X(=&LWCjniXG17MdK)432`k#AHLa^-#knG8[ojYNp6LI8`O4hM$^pfA-1=?FTV"gnShaXaC3m`bY9')eVS/j0i$n,u:&TX%n+0[[91r!ui5Di(g?278fq$^T*W^V&a20J]W#S+e16dOg7gaR&KaWt((D],O-)fR(oB%D#1ShjsDQBA&lDQ'`<$u-CmC&DAOU#sC\/>8M\9+lH=`.:TQF\3&5dA>7%/S=Y.Gd;Z&TcZ+86b>[^\[YU?OINBB&iYZU\!Aea7I&/RgYH$/ehrLUGEcp1Hr&n%0g>]W^?Vk=4P`krKG!!dqGH=6j2`*l'#),KlQ'?G#W?$H0ddhfrh`!Bl]qrUZ#4F=aJK!f2=1X?7@O~> endstream endobj 104 0 obj @@ -622,10 +622,10 @@ endobj >> endobj 105 0 obj -<< /Length 1613 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1687 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gatm<9lK&M&A@sBkgfl-'N#Y=;(Qn)>13%nTO\LQE3AYU1%#;KeNddOZ*_+4TlCW!i/FW`pNar$;KU]_0E>\Qb*da&ro?eYTlSfVJ@HscKo;`2k:oJ$(Mc%j($M6RDFXqIqa$Jc\fA8`)/+Q6W^!!Y9k=htFRP"eIaVrC'($10,#l[:W%FTin?uF01Efde-K0Z&2V>PE'?Z5f>^rS8$UYa'R.@qm+T!MJXm!KY\]_jktT;GSjmmP,/'>+A[c1k@;F(NmY!^H$o)EYIYfMpX^Hm7g-9`\!F5M/&?lK1%4<93&!4I:X6?bdIQ20%WRHSsV?Vikro#N\UdqU0/i+c:ZUDB6[uG74Qo$N@WE@uWhaiX:`jmm]T"":^aefOk,ak^g>*4em*]`5t:J,%9?LJkB332'>cg#*?Abig>o<-t)@8a`=725[I"_4uO'N_6lu=cH`PK'u^H?j4H$-Q"9MSN\[2!8h.iI_cS)QH;-E@H![];<&t&*HU6\j`NL[1R+Ytn)KZA_E#Nh,!]XsC5H@&^(au5MNcZm]$W`C8$'AL!kqKX+bYL^8Bj"\#4tbJsTgQh@0K,hD993hu`F/miCU8(!OC@+pRFb=T+V]2\"H?flZfIJSKGTYe2j-?[;-0s%R[l_q?`4YD6*e!ATV2LeQ'%H!_jCUke[q?+47uphh!52`:F?_8s!N<+%?ke#*1)\Os&\.cn=7cl-]d+OKV#Ac_J+!HM2#4)3m*1GcC+`(;&ggo?Z&(4iUTSI?%*rDH,4NqN1+M^;]b9PXE5Q)T\VAS4mX8H3]1+'f`pGEd3!qjCBBnsT85,^e5b?FVmA[H:,+oI5IDIX?jYh`CTG>HjcM2)h!cY/c?I=P^L`s!JO.*"?fE"er8nBH["uEmY@0(>o&WMQl?Vnm5%^OUUjO/*FrqXh)?6DR_Ka[bo#i-p6`f%gd,k5sl[ndP^`!H5GKcS+"O$O2((NN5Bp-QteF$amfM$f\h4GAGSihIpd:!pH-f^T_d(kT&uT4#%Nt4F08SLA3jFSo!\5DpTq>MPhQ*j5X,kQ(pcS&k_TOH?`7^)F*U]($J9(`)Ki_qACaa-*aR_7p(?$gbl=q&3f+85sZBK'9-Y4X@baS0e%cX-Gu`76.*;EobX7mZ?o.J=D!#S^l4(H3W.=IURbQGfJ@p7on^2hs!pl'<.XaVa:"Knb/57*8n1o*!WiW0rh,*Dpq!JK(13HCgcsZZ2*'g12jpr%uOl6XXWn6RhLD"Wc!4[Y.5*_:'@?f["$nV3+5TL[eHNH'W9WC@aDVgF.go%8n#GnK:PMBXIn,YEeRq6>^q[C,[m[2)!&M]\"h%\C_+imL%%BU@OE^TM#+eXVq<^~> +Gatm<9lK&M&A@sBkgfl-'N#M9;&$Y+DX'ZJ7?P#J06If47+h]Rd@mKufjA)iZHT":HC_DKP),pTR<^U[31?m5G/sQ=iMEmJb-3mJc,gcTFuS4nmqX?bF&X*,?-W4lZf=\=9?:MU^(URKU<9Jbh[hYVhI=*/36cmJVHuqltYE_pAXSo^Y2A>Yb/u#-oo<"%h6A-6fB0?'H2]i`b5oE>>[!$hhW(3W`T_]$Jn=jG3Y#B&oOgS/&<.-o^bOVU:1c78!F]Mb\eeA3#=u//@ek+7dW.KJ93&n:1>_)Q>o=ED!WFojq@"_\raLHRfSX,>fW:r^=Y-VH/bS2UD8'OQ_L.5G6p>I@Ts'02rLGa._^;2P%j:GUQU[i^J'VCkInh0[@XqBrLaB[buD%j;@P2Dk!/I?O]Il0o$]r1_%U'_Ca/:m0bs?&.NedAHL]tg[$Ke8OhB88PTR^\:,*%=,hVR,$5o/EdUjq0+%IdS7$8(hULWs5*F$l@kRd78K,s8;aael7&oTo]::8Q$qMo&$YEBr`Z^_m[J4f3[5[`Gi;,T\Q.)s5RF#.g[7E>sT]r>/N,[cF#E:C0$JF](1k1A2&M?=9=j4#\M["?\L)9SC7:sp9[2j-*BJ8W&n_?nh_(I8k6!Jjm*n?Wo*$^19s#W`d+-#:VsL<*D#3#(5gbR]H;eWk+6Ge%?bV-MRc?uA9lQC`'+`F'*pCV9-'eUSfAh9bnYiunHU__G+,c[feRPokNaDILEPp7,LiBK[sL?T^%s"bZ!j\eE%1AZAm=_X(N+8P3KXZn3pJOcV?B&'oHsOH%[@jq"Mh!R_j1H&dq83CsYq@=,;SY(3s#Q2S/HS,.RVqTmMe'Mt+[/3G*1it#OU7XAP*bhJGbcPZ')Fs=ceV6cM^DEIg;"rU=2E2d_SSSaLW+QL[AE'C_NYgM&7CJqKW`2kenUendEpWS_F/]m$MPn76P1.+q(LWZL!AL8fVM]af*(5(uZ^O^*5mALo88'DI!=LTMNh+^6io4+_&*/&d.@4tX=Tl:OkcPoaj/l#>0:Qs/;qUu[k0rJoKdDO<3!]+="78N:>Q3OS*DWZIEYcIctQj/"qGE>iMV!(ot*2mgAOdF+;QKBE%/kpU>"*UGIn;.LS0T@gNU*>Qp4Mb>>.g5S!pmH&,"^A/+TMMon.L7cWUG)rd4kb*FLB0ZD+90G5\_S'F_p"?h9h>iU]&,EUD&DoN>;2p+(!j5i.J5@TLj<;~> endstream endobj 106 0 obj @@ -637,10 +637,10 @@ endobj >> endobj 107 0 obj -<< /Length 1842 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1791 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gau0D>Ar7S'Roe[cs%,*AjfPHAK:t+?/2:/Z7^:+!QuMuS$E4=U+=Bsm+7;]-1aq[D&:h93&W)R>eY:BolP:3*ISr:DkT?:7Z!1R0+:5@5@Db)0r$o>)"fBH4cOn4>ou3piWp.#rG'239[oPG2Y,U$^A>b(p*:k2oE0$Co):\b'@f_SbgSSU/ejkBh"c3mK3k)(SR%iCX3[t^QOg`l\L9,D^V/mP!EG"Scr8cfZVnGbX1=Jup(9;5fJ8_<&a5i_MP@c5lQVV%?AVAUITbg>V-`;7?G5EGOX]uQT^b.o88WlI+e^G?3"T]1W@D6*`>a=0,9$V6:6=?8E0EUST3BJ8'ea3/c2l*&E%aU_kN,#p=c9qGWhdUg,@HPE#*f$?!MYLX:@lnb&KO*tJF4m=lWhRHW1K;rTRt"8NajRB&OUOK_.!&]AC"W7U/X,,O_'+;q<=&85UW\DTs6@qc%4ZXJ-tPu[l66)H6j`K%)47eX-[).(mDUUkU5sjC&">a0:9Rog($//U[>[glM1Rf?9NUdH9Tl!T?`#V"gM>A6epPi*H>^/cHK7e1]90:SB61#7s,>OL1mc;E*W-Ls"<52l.R:WT3P-AA!o!9@o4+tK=]LX@3:"*oFeeU^jH9F0LiR-K:N!tg:p9[DQd(IA#LTfs.,0fhm[4L+97hl7i7NWZq=bU.90M.$`-#\bUT2&8bcl=?$3rYfd9mXnh>F^f3FbU;Y%fLN$;@@1t8d=2$Uc]!7#Ejm9ZfZY+e/dNdJ-_UGtRP`@&-h<*:1/&;9TNPF-42XF"0sq(%O?TSr*u=&[UWUi+kJKV5,R2h;[Q0iZCZjtQHFrK1(!jfTXrA=6;f*j6ha29(gF2I;_0pZcJDPdd^V@=K\o>N[G0lrX%[LH9cS0lSpH?CP%umtk7s;t-P5oh_7.Ga=.WYmW9E[=Q7d:Z'$%j4XW:n7VM-pnj"2O8PN#C#l4>gTY]1db,7+jMr#$C:PX!cPJ$NiG$-Y[M6MVN>1ATm2f$./\6Yi=8O%C2s/'-/mTKA)QVR;nF!!3/X']V%;Wiq?]8="lkM'&Xmb252r%CPEq'ka7Ek'&7aRnR<4!q.ZX>4XN`ZTraNY>PcKhP:.^5q(J3T0?m!sA$sL6]-ie[GgR%*Q&PF3\U3/PM6@75lT,Ou&_?Rp=l4F2X3<'cj/E^gfn~> +Gau0D>Ar7S'Roe[cs'D`B#KUFCG;FGln62AFbuRt=SAE?PV#-9>uAnD^ODCuM2-t%HbbBOZ&_;EbBL,MeU03EO1pUXZVmDkUW>m,j86Recb/Q;`+&p)O#dGg*_1^=Y)[Cm,XO[sIPLF69[oPW132\dY56&]I]#\tmkSOiEW/$!OC^AFfZ89^K[dZ[+3m_iC`_Ht-^2Z5R]'GN%MXcQDCAfN5*fG+S9bNotZJ^GS?bh(f3NM3)-2.eGZo7^:e+>O/L1D,sf^=#fc,0cf1EOOm5\0ER+-[.n-l67nA1q-j\-]]_7]8?,7PqiQ@a8$@8@*#%*E"E(CFhf(7n!W22b?![2k@%n$MK^d>?ZQPK`!&(N39:Iq\JgR,P1j))e^T+YRYJkQ2%@YBDpL_g9"o1\*T3TP+NF%--fh&AXVo"#G"$cYR^QPTW5u22.Q.8cU?Ymn3W>3L);=,VLbCa`Nde0fWDSbiC^2#6UX)pAIk[Hl(bm4F2U)C42HCnIib]$]!7de86GfP';Z@bXrUSb?ot=R=$OF\F$:>8$21F"PXebpeAE/.+B$!'AuujX7\jp7cU/M13>J[+9JYLms?`1JV/1qB]8GUJ:mX.:t_UI'o]k`"TN[(g1,W:\hY($RL_)&[rE"tqN@nfC,X5ng9W2PC_Yjk27N5ZP@n07/]P]nc!O@_[RnSB)`*C[A(ZTKR\Y0+KPQVg,*J,tpIhI[1=`pq>-%>rA!d%<8oO=iScdYFS>2ZgJArm*R%TU\A3%R54HmFtu\SXeK8RaMi0r3#[UXddB63FSC`.U919JE@>i0Y1P^*S0f(O#Gp*sKngsK9V0t0]gL>Y8F=k]*mg\MB\IJe,442%%dE5DY+!SUW4,4^YTkqaa\D+%LcU%5W0a>U^o![8MVpqJ5B=Hp*,!j%i;e/!WL%W[qG*KN\t5qhhVJ8&0)#ut3oCDNjTJk=J9Ug',Y[4l`bMuoV2kJ-F#4?"?V%'#6bm`DOJ=7q4BP/q;reJ7'b))kA(easar&[1IV8_[tKT[#%H_k9m&F1a8^i endstream endobj 108 0 obj @@ -652,10 +652,10 @@ endobj >> endobj 109 0 obj -<< /Length 1225 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1257 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gau0CgMYb*&:O:SkV3*I7\iFXMBYL<`dlk_aJNr;BO!'Fkl#M'!)BL5-\m3HO/6b8!CbhS3CrpMaVm;:og"&@:bm:(DO/pFUh=C,7p(2E4igd>^1/rFC3d^S3NH$NmH3`Tr4c%bDf.aGjc+Ho9U_cumkLHJ)hGY;0jRhS(aW3lRWscnH/C,WYa$^)f_"YcN%c.q^Gg-d>=)%AfU:Gd\^qb]4iM;$5;[Y6Bk`P*V5P/)HXRPSSE3CUp,$>sT*HU+^q$RX5Yh^XIpHlL+L[r]'EmEJ1/Z3rW%Nu5TW<0G)X1[3ULlf,&[Ei8+T,QORLM6d+qg`Lr`X3Tmu!$L>q#"a_-iMXLm'lggtc721]6%*H7!KM$[%6A8Ok$[lL]dV7m'I=;-U$DCbJ3T(1%+']"*R83:tlVNL?_E;-'oPE*DqBpBgF,W8Ba'W]at=PS!GGbf3\k7#cC7Hi#sOFf8OaF-.Apn%#?Jans8im>0'dr1aLVSJBb1Xkd82n.]f`o`X+fKVEi!kgf""02%_d#K30e=;1X6q2!`5:Lf[$1tEhdX;PE#"PGMZU\*P*D)D9^uCBGr*ZG#oA;im,V^,D*UXcJl^IA7nWHl[[02l+>HX==h"Dt-Z4H[ORLKma-D`fB&JMXR/k:X=+TZ7o>t>K*1>a`&"X&G^&~> +Gau0C>AqtE'RoMSaQ"Vpb]_uN&/o#:+OCs8$[Vo-6K>G8g8)[40)m!Us$>c#C4ODDfSle>:Lb5&;"-`s);79PEl0DGotPa.LH=L)$X.4lA/L(sc'M\T/W;/^nEfpo0CkU057f/XZ0>FPB5KTbeF!Pf"BD2t_?-QG%].l)+tj=K3-!UeGJNP=UUUb_ODk"M:$Edl9nmaXD+_Pb6VqQ1RkGt#UZ(3Xh[0pHKTnf%oD,?uinO'/R2-[qX35f&NOtlIO?Yif]./*_UkAhS;G[/P7[,`KlsSH34/Waj53NS88aK?qY?@$ob)SYmIsMe.I/EU5qV>`<6tc)TJH=Lo2rX>9okC_k@b%BgHq[Xf2(5!$[7KrF%.6hR#T=G-0QALE2[i\Fk`sj0H-i"u4i_/a^9?hueC#'/Mm?HRm84BH7=DI>I3-0`K&CChJ0(6O9sOrGTa!*WGFs^l!`W7C*RGPTG^!@#>iek:BXC3O^L@os@5)92F]AB(CH$73n>nbV\'%?rGGI)=BrTB(eFnM9LniJa'D3D++f_NL;FYsHE:H`a)Au%IosmhhH>=KiV5*sK9+SZ\qjV!K"96iHZ!F--NN1o@!=iM>,rb426)*WQD$?f[S`_OXs!fM/3W'5MDuN.Qp$i-DC?-I%1YIEr3]k&5(4/!%foktrD)=_W`YQO>d.Zd"[^da$m+M&T=R'-rB$+"XlbV2$825#o#glU*pIk#AlHfqY]"6!qBTem@PWs'jaa,^3Au`aA0/KiinRWrhqQ,"XnR"X:l2dkgUsR0^c(+p`Hdl5@,G5k\CWVTcu,;Lt%1XG_1&o"/]'[1Z[#*6=)FlAh^L9&:Z&CU5r~> endstream endobj 110 0 obj @@ -667,10 +667,10 @@ endobj >> endobj 111 0 obj -<< /Length 1887 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1867 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -GauHL8T3WI'YaHG#e;cXD+2sWU+"A^l9U:n-Z.Z40U[P;;79:mFL=+%TKg/d(@s\WE]baH"HH36I-^Mbh5t9RX_*(/LplH\UM/T2,GQ/NRplC!SR(A!lfN%KGIcq`&%[o(bcokn.";X2$l2Te.pW/N1ifc`InO`2[8*#[U[V"f>r532$\.I?Y-T!@:7"b4M#iI"hatl.H1XlfFo^2EO_HuY,Ns\=Lp_!iW:sNZ:j7>nJ@GVE2=%0LPNH&&V,qDiok!nA5U99T=Tt!)l+kKf2PSMk[,f53ti\X5?aZ6Dmi-:he4_tI(;,_KJ0_=p+!J$dPj".9r=&k9"D4)82Nqete's7KX2ZU]d>!hbufaH5>2U?c-GF=``4'4Z^8@02D>N40n$T=T3G+qRa*MCa#-*`n92?d5=7?EV]5&\=#r+Mu"5O(1]VcXLTt0VpeDqTE'bhT%?&&u^f\Ra*jU%]\b:\sp%QrQg81+T3U?WY**XHX[[:uIY/r>Yo3f2Go>,H,1]L=C/Z3D606pne.65R\iX[/+T2W=^[X(b>#+e^BA9ebifWT(W489b,p'4e[E$8SJCp5L!h+8_-).;M4W_\]4J=Mlc'24ooQZ7+otXOA2OEYi6]H#9]fJ!\eJ__BE.d:Bb\S!VF5$pP%[0Wg;s7te]U/oDm-1F[)mm$&iU(I2+[39srKXrsCT='D?&RPGgFTOP))n]TLEe4].ZSr?PW"etP(g2X^dBrZr.V?b$LeYgtb12f;Ep1Gh,rmLJ[Qqooh#RO3m])pA'WRj)=8m?>9b`SEN][FQ/Z(\,,-%fEs32tWH(cg1\k!JEfAaXZn1Bltl)BY=5fhRs`^Ca)O%e?E(?\@3>]+\<"UHMRdM\qf8MI.uJ5o2:!*j[&jUj-"YcKO+(HWQ*M#kbTAgkg"a=&&t1'cOb-aPpoiSXof2NmuK,jKL5"55IGF?s*0aVA*\]JpL!N#sS;S.\aTL_I&_:8kP6!T2?!1+Rpq,Ao[nBZkFo,^po(WVabb1Rt[_/uS"?9?_cS`,r%o#G"]X:#*#6AABZg=S'\^@iJBLW]>=?E,l@a=;[6UNdQ0cVOXE(H3K#Ia&I]uZ8n)Da/Ud$TXLif1,/S"B#_pUY`m$!^!l3B#,''(=KH:oa^?*b#KN&h#`tH>sGTiIdOi$m4?5@'oE2q#M67T/m@*H=S(l\mNe11jo,Fd+b:g~> +GauHL>Ar7S'Roe[&G!+0M]#B9!Q0Ga=b7F.RP!Cid.BVd.9i/bHBOdkYoc2.[*3T%13#$V#TTgrrZ_\5!`,idVN^ht,3Q8.tbobFF@@YHuD202OkF?i'Q:Fm)XtCb:O445=kq+*FM4cUD81+uaHV[Ia4dhXeT?6%KN1:2bDZp*FW04r$N,HL\pP%j#&'VH7'L>Lr'3e!frFf'86D?%U*[CMUV0A@]4QfBWhbh67\B^kOjs#<6n]6GN_HL!HqkD?hR^cS4\QqBQr$8(p]u93WY$D7aj38+B4f7CW.A1o=m!"@mi8#dja=efd=D"%uU>dC@7^;ZP2,9QjDIFED]`_bHZAWZ3k@*4u(AKl^0O(DH.X;.6W7Yh,:HFV4tnnfmJ^s$k]-sm;@.dN$p9niqQc3t@RW1re]QiRaNaqfjfcQ83$]0:"W-1Nf+p.&61V&Po*il=)O=F#^UVDsN04VVXt,\c97Nr0A8Q/A:)-B?QX*;dY2DB)[16OHJ55[;eG>[5;Zoi5iN798$qOJLB)&uQuZBO7s$oapOASo8E':)t#fobTn4P;J(c1&N^KM5A*T;?TQVKF94XO;3WA!GKr>R>o9HdPnK>(_,RF*-gh\m!@HDJ<7jFX]I@e+CY+1.i[iNCreE]'W!XEI,^3UrD`H*^0Q:X\RFlQ`rijk<6_Rf/L6J,5U2+(_:k&Vb$30W%GsK[%Q'F:/@ks*Tqa5AUY>S,rEuc)1VGT:s/6a+YD9:HbPA!u$Ju.=qX_n9=$Q=+Ym!\t"2+(LgE:*$-.>q8ul)i;e$_4/Xd`Xt#92(o^2D\F2rA4TIt[)>2'97O50oD9Ul:Bc$=_A^)Z?pm,K_oruU\i$/MnH,EZl&pOOW5%`?2]h1fKes:"G23c]<^HlFtC<'c/H*pp!NZ>r.06+BY!5EeJfV>>F3NR@b'NQ(/p>/hA?T*L_"Z,QEkoF!MYe!Bncb?;hV8?1nhI6'T-_4'J@b[P6ACi9(mL7F##A=qg&JI#Z-\0+G+W>ML-cj(WHa=-@9$:KH7d.'h1bJ]`MA_!QZ,sOQ\_HUF%^jM^R^5:u%tsno2O5rDX,g:ps.'4mq*OG*\]EnWl1U?[X4hhn,!(Lg85cE',3_:t6UVC[D42FidXDg;YXSq[LSK\U4l[A4u9aMSI'o,?-CnYdNR5Z:LRZnVsoj%4q*XBHqTi(eE]H[".RD26qkY207H):8l3`"\W+P=QILp?fu'cB`Eg"#cW>IP;B`?,_?&cNPdh4#=E:Q-,j8Z+]_4j,&Z2FiULPAt>Q#9<3F)#/*CN>.pU9//&7?$LB"2>oF1]L>U9^>^K44JqNS;(8DE5dTmO#&K,`<;g;dj8"OeuELX9=Dp?\p]sJm8\_]4*H=NoGBJbl*;&(Eq/5jE(.WU@^b*f1FB-M)T3=SLlmmOn7@=?1Srb5G'e]tQB/qu endstream endobj 112 0 obj @@ -682,10 +682,10 @@ endobj >> endobj 113 0 obj -<< /Length 1153 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1246 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -GatU2acbC:&A@B[E6Ga@!s9[^jcDhVj`/u86XhRf+d3!R5pC+X*-9M0(Os&dMhD:'aVh!UP0a2THef4Jh/`%#\bNhqA-_#DMj.(.U*tWN:j1l'_5SQB-EG*-MnA0?IX*RQ(U1.!/m,T48;p17W8DpP9W%l;BCK44>GgR!07X"i0X_r!"ESj"o$:VVGW=%D2lI*/&DAq6$Lr(m:Opd/EI&lsU7,[0THBqAE-'ZBcbK4i97u_Qq_A(^DU4JNPb'Z"FH`5%3##F:Y9OC-*fT#l^0R:gb3cec(PspOUL'mUm'^ZdT:+j!]0P`k]P:1/c#"$c[S5;RqF$5A(2W$Kead@"KGD0BnjQ`e=Lr1a,k?_^=;s6jlcTm7S=Pg(uF*OIhWm+B`>U5]c^Yl?Un16-/Y[rQQ0_Ht$&VFC-CTc9W2/AK?#YeNt=A[W3-i2+icU2-(pX\:!Cs/hT%;Mi&D;EDTI5_&fCsG==__L-rs3Fp^8/e_No66b96DcT1BOKurVq:jg[40_0hneKRQa3)&0@285,!)8K'9qhu@(;#,RL2h2Y.-`%JVM)(4OknJmDdYJjoMHNZI8aRT +GatU3968iI%)2U?n@$G4_NL-S8NYBge(0q1HK`7`&">`'2Jo]L;6Cs8I+dDkeAEU]9C?=P)92eI&AX&3+FLYc]j8j2c7%D8ci#C=QlmQ*q=!q;q:9327tj@Sfr*NZF*GBdF$uFAZ.R8kX$k/R7@bW8=:cQ+1A'2K4>3kb/Se.mP#$)+9BD.=;&fC;-*iV5N1gdq6EIOn<=(SK[2!_Q*i:hnE^SN>a!PVeZ3$W2\W:r"pG&jM?tK`;l;Feb]LICG`VTZI*l\*jLki$Lmr\5A%G\4L_!]+jnk_ofO-,9Y_ZRT/I\FDZJLcCtpcqT:a4>M!megtTa(h]aVPm7mJ6"fh:,.4g^aGh_XV71u83I$iYAgL_q93IJZit(fTCAA+mbGm0%W@PdVLA@6?C1D>;"1`4ihoGW(8)V?K3Xa"FTo"I`0r`0#YAk&'Dbq)L%2`W=2[hpK0c(gba8Ljb6:L.HHifZt->JfJ0pAjHJN=$InWV,\1PA%oK/QSBos5]a;*m3LB)oW<1tbUb^u*OaS,UsY>KUgFV@f3lQXN_.99lALAh0.gWJF';K;*Y)O&K/uCUo;f'KAE^#]'8_F=Zk,g]A5!873"/*6#^OY^am->UJ-?,)]l"r_]$4pn?"d5e,e`3#ZJGb&+cBGir8nX4h.SH1u>3d,u`h'M6/;*G0hb^&SRQ!KJAdW1,V)9B62Y;#--nmQ**#4tV`oLHrmrUsFX8#7]\T'rg+@Ae5lVaFF93D[&3gV2^`?a:B&9U0E'L#Z0-o<_>][$o%/EA4P*i:LRXM*?,X"O@%.Af?afXFUK[uU+KaM63H]J"B=d.5GLaI9ZS9c55X%X:3s&^5JUMJ\BK(`g348ViAL..Rh:H`oZR>Lsp++Dse4Pg/i7Xu6c=Dc"`!,WH-ZK)k;aHCaL7L"[k*j\6ebl]Z=',t<]pd\974'``Q^r$C6"O8Y,mDIoEkH>P11=%cIB['iUMRgLY=EfDYqrrHk7.;]~> endstream endobj 114 0 obj @@ -1030,25 +1030,25 @@ endobj 11 0 obj << /S /GoTo -/D [78 0 R /XYZ 85.0 624.6 null] +/D [78 0 R /XYZ 85.0 611.4 null] >> endobj 13 0 obj << /S /GoTo -/D [78 0 R /XYZ 85.0 449.866 null] +/D [78 0 R /XYZ 85.0 436.666 null] >> endobj 15 0 obj << /S /GoTo -/D [78 0 R /XYZ 85.0 359.013 null] +/D [78 0 R /XYZ 85.0 345.813 null] >> endobj 17 0 obj << /S /GoTo -/D [78 0 R /XYZ 85.0 212.56 null] +/D [78 0 R /XYZ 85.0 199.36 null] >> endobj 19 0 obj @@ -1144,73 +1144,73 @@ endobj 49 0 obj << /S /GoTo -/D [92 0 R /XYZ 85.0 196.2 null] +/D [92 0 R /XYZ 85.0 175.0 null] >> endobj 51 0 obj << /S /GoTo -/D [94 0 R /XYZ 85.0 611.4 null] +/D [94 0 R /XYZ 85.0 585.0 null] >> endobj 53 0 obj << /S /GoTo -/D [94 0 R /XYZ 85.0 560.147 null] +/D [94 0 R /XYZ 85.0 533.747 null] >> endobj 55 0 obj << /S /GoTo -/D [94 0 R /XYZ 85.0 307.694 null] +/D [94 0 R /XYZ 85.0 281.294 null] >> endobj 60 0 obj << /S /GoTo -/D [94 0 R /XYZ 85.0 255.36 null] +/D [94 0 R /XYZ 85.0 228.96 null] >> endobj 62 0 obj << /S /GoTo -/D [98 0 R /XYZ 85.0 545.8 null] +/D [98 0 R /XYZ 85.0 507.4 null] >> endobj 64 0 obj << /S /GoTo -/D [102 0 R /XYZ 85.0 489.8 null] +/D [102 0 R /XYZ 85.0 447.4 null] >> endobj 66 0 obj << /S /GoTo -/D [104 0 R /XYZ 85.0 193.8 null] +/D [106 0 R /XYZ 85.0 659.0 null] >> endobj 68 0 obj << /S /GoTo -/D [106 0 R /XYZ 85.0 230.2 null] +/D [106 0 R /XYZ 85.0 173.747 null] >> endobj 70 0 obj << /S /GoTo -/D [108 0 R /XYZ 85.0 371.8 null] +/D [108 0 R /XYZ 85.0 329.4 null] >> endobj 72 0 obj << /S /GoTo -/D [112 0 R /XYZ 85.0 534.2 null] +/D [112 0 R /XYZ 85.0 521.0 null] >> endobj 74 0 obj << /S /GoTo -/D [114 0 R /XYZ 85.0 637.8 null] +/D [114 0 R /XYZ 85.0 616.6 null] >> endobj 115 0 obj @@ -1221,160 +1221,160 @@ endobj xref 0 155 0000000000 65535 f -0000056107 00000 n -0000056321 00000 n -0000056414 00000 n +0000056176 00000 n +0000056390 00000 n +0000056483 00000 n 0000000015 00000 n 0000000071 00000 n 0000001329 00000 n 0000001449 00000 n 0000001635 00000 n -0000056566 00000 n +0000056635 00000 n 0000001770 00000 n -0000056629 00000 n +0000056698 00000 n 0000001905 00000 n -0000056693 00000 n +0000056762 00000 n 0000002042 00000 n -0000056759 00000 n +0000056828 00000 n 0000002179 00000 n -0000056825 00000 n +0000056894 00000 n 0000002316 00000 n -0000056890 00000 n +0000056959 00000 n 0000002453 00000 n -0000056954 00000 n +0000057023 00000 n 0000002590 00000 n -0000057020 00000 n +0000057089 00000 n 0000002727 00000 n -0000057084 00000 n +0000057153 00000 n 0000002864 00000 n -0000057150 00000 n +0000057219 00000 n 0000003001 00000 n -0000057215 00000 n +0000057284 00000 n 0000003138 00000 n -0000057281 00000 n +0000057350 00000 n 0000003275 00000 n -0000057345 00000 n +0000057414 00000 n 0000003412 00000 n -0000057411 00000 n +0000057480 00000 n 0000003549 00000 n -0000057477 00000 n +0000057546 00000 n 0000003686 00000 n -0000057541 00000 n +0000057610 00000 n 0000003822 00000 n -0000057607 00000 n +0000057676 00000 n 0000003959 00000 n -0000057673 00000 n +0000057742 00000 n 0000004096 00000 n -0000057738 00000 n +0000057807 00000 n 0000004233 00000 n -0000057804 00000 n +0000057873 00000 n 0000004369 00000 n -0000057870 00000 n +0000057939 00000 n 0000004506 00000 n -0000057934 00000 n +0000058003 00000 n 0000004643 00000 n -0000057998 00000 n +0000058067 00000 n 0000004779 00000 n -0000058064 00000 n +0000058133 00000 n 0000004916 00000 n -0000005669 00000 n -0000005792 00000 n -0000005868 00000 n -0000058130 00000 n -0000006000 00000 n -0000058195 00000 n -0000006133 00000 n -0000058259 00000 n -0000006266 00000 n -0000058324 00000 n -0000006399 00000 n -0000058389 00000 n -0000006532 00000 n -0000058454 00000 n -0000006665 00000 n -0000058519 00000 n -0000006797 00000 n -0000058584 00000 n -0000006930 00000 n -0000009251 00000 n -0000009359 00000 n -0000011367 00000 n -0000011475 00000 n -0000013841 00000 n -0000013949 00000 n -0000016590 00000 n -0000016698 00000 n -0000019333 00000 n -0000019441 00000 n -0000021807 00000 n -0000021915 00000 n -0000024081 00000 n -0000024189 00000 n -0000026180 00000 n -0000026288 00000 n -0000028791 00000 n -0000028899 00000 n -0000030670 00000 n -0000030778 00000 n -0000032434 00000 n -0000032542 00000 n -0000034086 00000 n -0000034194 00000 n -0000036009 00000 n -0000036118 00000 n -0000038107 00000 n -0000038217 00000 n -0000040382 00000 n -0000040492 00000 n -0000042199 00000 n -0000042309 00000 n -0000044245 00000 n -0000044355 00000 n -0000045674 00000 n -0000045784 00000 n -0000047765 00000 n -0000047875 00000 n -0000049122 00000 n -0000058649 00000 n -0000049232 00000 n -0000049432 00000 n -0000049650 00000 n -0000049856 00000 n -0000050064 00000 n -0000050232 00000 n -0000050432 00000 n -0000050590 00000 n -0000050765 00000 n -0000051028 00000 n -0000051269 00000 n -0000051398 00000 n -0000051552 00000 n -0000051706 00000 n -0000051850 00000 n -0000052000 00000 n -0000052141 00000 n -0000052376 00000 n -0000052571 00000 n -0000052811 00000 n -0000052993 00000 n -0000053166 00000 n -0000053369 00000 n -0000053557 00000 n -0000053809 00000 n -0000053950 00000 n -0000054159 00000 n -0000054345 00000 n -0000054519 00000 n -0000054764 00000 n -0000054955 00000 n -0000055161 00000 n -0000055327 00000 n -0000055441 00000 n -0000055552 00000 n -0000055664 00000 n -0000055773 00000 n -0000055880 00000 n -0000055997 00000 n +0000005670 00000 n +0000005793 00000 n +0000005869 00000 n +0000058199 00000 n +0000006001 00000 n +0000058264 00000 n +0000006134 00000 n +0000058328 00000 n +0000006267 00000 n +0000058393 00000 n +0000006400 00000 n +0000058458 00000 n +0000006533 00000 n +0000058525 00000 n +0000006666 00000 n +0000058590 00000 n +0000006798 00000 n +0000058655 00000 n +0000006931 00000 n +0000009252 00000 n +0000009360 00000 n +0000011458 00000 n +0000011566 00000 n +0000013932 00000 n +0000014040 00000 n +0000016681 00000 n +0000016789 00000 n +0000019424 00000 n +0000019532 00000 n +0000021898 00000 n +0000022006 00000 n +0000024172 00000 n +0000024280 00000 n +0000026291 00000 n +0000026399 00000 n +0000028817 00000 n +0000028925 00000 n +0000030805 00000 n +0000030913 00000 n +0000032564 00000 n +0000032672 00000 n +0000034182 00000 n +0000034290 00000 n +0000036138 00000 n +0000036247 00000 n +0000038138 00000 n +0000038248 00000 n +0000040323 00000 n +0000040433 00000 n +0000042214 00000 n +0000042324 00000 n +0000044209 00000 n +0000044319 00000 n +0000045670 00000 n +0000045780 00000 n +0000047741 00000 n +0000047851 00000 n +0000049191 00000 n +0000058720 00000 n +0000049301 00000 n +0000049501 00000 n +0000049719 00000 n +0000049925 00000 n +0000050133 00000 n +0000050301 00000 n +0000050501 00000 n +0000050659 00000 n +0000050834 00000 n +0000051097 00000 n +0000051338 00000 n +0000051467 00000 n +0000051621 00000 n +0000051775 00000 n +0000051919 00000 n +0000052069 00000 n +0000052210 00000 n +0000052445 00000 n +0000052640 00000 n +0000052880 00000 n +0000053062 00000 n +0000053235 00000 n +0000053438 00000 n +0000053626 00000 n +0000053878 00000 n +0000054019 00000 n +0000054228 00000 n +0000054414 00000 n +0000054588 00000 n +0000054833 00000 n +0000055024 00000 n +0000055230 00000 n +0000055396 00000 n +0000055510 00000 n +0000055621 00000 n +0000055733 00000 n +0000055842 00000 n +0000055949 00000 n +0000056066 00000 n trailer << /Size 155 @@ -1382,5 +1382,5 @@ trailer /Info 4 0 R >> startxref -58703 +58774 %%EOF diff --git a/lucene/src/site/src/documentation/content/xdocs/fileformats.xml b/lucene/src/site/src/documentation/content/xdocs/fileformats.xml index eacbc16c3e8..17ca5346a9f 100644 --- a/lucene/src/site/src/documentation/content/xdocs/fileformats.xml +++ b/lucene/src/site/src/documentation/content/xdocs/fileformats.xml @@ -90,6 +90,9 @@

In version 3.1, segments records the code version that created them. See LUCENE-2720 for details. + + Additionally segments track explicitly whether or + not they have term vectors. See LUCENE-2811 for details.

@@ -935,7 +938,7 @@ 3.1 Segments --> Format, Version, NameCounter, SegCount, <SegVersion, SegName, SegSize, DelGen, DocStoreOffset, [DocStoreSegment, DocStoreIsCompoundFile], HasSingleNormFile, NumField, NormGenNumField, - IsCompoundFile, DeletionCount, HasProx, Diagnostics>SegCount, CommitUserData, Checksum + IsCompoundFile, DeletionCount, HasProx, Diagnostics, HasVectors>SegCount, CommitUserData, Checksum

@@ -957,7 +960,7 @@

IsCompoundFile, HasSingleNormFile, - DocStoreIsCompoundFile, HasProx --> Int8 + DocStoreIsCompoundFile, HasProx, HasVectors --> Int8

@@ -1083,6 +1086,10 @@ Lucene version, OS, Java version, why the segment was created (merge, flush, addIndexes), etc.

+ +

HasVectors is 1 if this segment stores term vectors, + else it's 0. +

From be2382efb7d76230169f1b35334ac2311b4e958a Mon Sep 17 00:00:00 2001 From: Yonik Seeley Date: Wed, 4 May 2011 20:07:19 +0000 Subject: [PATCH 17/57] SOLR-2495: json parser could hang on corrupted input and fail to detect long overflow git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1099582 13f79535-47bb-0310-9956-ffa450edef68 --- dev-tools/eclipse/dot.classpath | 2 +- dev-tools/maven/pom.xml.template | 2 +- solr/CHANGES.txt | 4 ++++ solr/build.xml | 2 +- solr/lib/apache-solr-noggit-pom.xml.template | 2 +- solr/lib/apache-solr-noggit-r1099557.jar | 2 ++ solr/lib/apache-solr-noggit-r944541.jar | 2 -- 7 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 solr/lib/apache-solr-noggit-r1099557.jar delete mode 100755 solr/lib/apache-solr-noggit-r944541.jar diff --git a/dev-tools/eclipse/dot.classpath b/dev-tools/eclipse/dot.classpath index a5d64f92dcc..0f201536149 100644 --- a/dev-tools/eclipse/dot.classpath +++ b/dev-tools/eclipse/dot.classpath @@ -95,7 +95,7 @@ - + diff --git a/dev-tools/maven/pom.xml.template b/dev-tools/maven/pom.xml.template index 95987f4c141..546040851f8 100644 --- a/dev-tools/maven/pom.xml.template +++ b/dev-tools/maven/pom.xml.template @@ -699,7 +699,7 @@ solr-noggit ${project.version} jar - solr/lib/apache-solr-noggit-r944541.jar + solr/lib/apache-solr-noggit-r1099557.jar diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 831472aa7de..877183cba80 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -315,6 +315,10 @@ Bug Fixes * SOLR-2493: SolrQueryParser was fixed to not parse the SolrConfig DOM tree on each instantiation which is a huge slowdown. (Stephane Bailliez via uschindler) +* SOLR-2495: The JSON parser could hang on corrupted input and could fail + to detect numbers that were too large to fit in a long. (yonik) + + Other Changes ---------------------- diff --git a/solr/build.xml b/solr/build.xml index 8c68ca3464e..80e66fd984a 100644 --- a/solr/build.xml +++ b/solr/build.xml @@ -1020,7 +1020,7 @@ jar.file="lib/commons-csv-1.0-SNAPSHOT-r966014.jar" /> + jar.file="lib/apache-solr-noggit-r1099557.jar" /> diff --git a/solr/lib/apache-solr-noggit-pom.xml.template b/solr/lib/apache-solr-noggit-pom.xml.template index 1596274c115..85b85a4e7d1 100644 --- a/solr/lib/apache-solr-noggit-pom.xml.template +++ b/solr/lib/apache-solr-noggit-pom.xml.template @@ -31,6 +31,6 @@ solr-noggit Solr Specific Noggit @version@ - Solr Specific Noggit r944541 + Solr Specific Noggit r1099557 jar diff --git a/solr/lib/apache-solr-noggit-r1099557.jar b/solr/lib/apache-solr-noggit-r1099557.jar new file mode 100644 index 00000000000..9fb87b9f301 --- /dev/null +++ b/solr/lib/apache-solr-noggit-r1099557.jar @@ -0,0 +1,2 @@ +AnyObjectId[5c4007c7e74af85d823243153d308f80e084eff0] was removed in git history. +Apache SVN contains full history. \ No newline at end of file diff --git a/solr/lib/apache-solr-noggit-r944541.jar b/solr/lib/apache-solr-noggit-r944541.jar deleted file mode 100755 index e0624dd525f..00000000000 --- a/solr/lib/apache-solr-noggit-r944541.jar +++ /dev/null @@ -1,2 +0,0 @@ -AnyObjectId[9b434f5760dd0d78350bdf8237273c0d5db0174e] was removed in git history. -Apache SVN contains full history. \ No newline at end of file From bde0e76eabffea4172bb99350430834515863431 Mon Sep 17 00:00:00 2001 From: Steven Rowe Date: Wed, 4 May 2011 22:02:33 +0000 Subject: [PATCH 18/57] Fixed jar output directories, from David Smiley git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1099620 13f79535-47bb-0310-9956-ffa450edef68 --- .../contrib/dataimporthandler/src/extras/pom.xml.template | 4 ++-- dev-tools/maven/solr/src/solrj/pom.xml.template | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-tools/maven/solr/contrib/dataimporthandler/src/extras/pom.xml.template b/dev-tools/maven/solr/contrib/dataimporthandler/src/extras/pom.xml.template index a9ee1f774b3..9c08baab4f1 100644 --- a/dev-tools/maven/solr/contrib/dataimporthandler/src/extras/pom.xml.template +++ b/dev-tools/maven/solr/contrib/dataimporthandler/src/extras/pom.xml.template @@ -103,8 +103,8 @@ ${build-directory} - ${build-directory}/extras/classes - ${build-directory}/extras/test-classes + ${build-directory}/classes + ${build-directory}/test-classes main/java test/java diff --git a/dev-tools/maven/solr/src/solrj/pom.xml.template b/dev-tools/maven/solr/src/solrj/pom.xml.template index 072e1ef5286..3ae76473707 100644 --- a/dev-tools/maven/solr/src/solrj/pom.xml.template +++ b/dev-tools/maven/solr/src/solrj/pom.xml.template @@ -85,7 +85,7 @@ ${build-directory} - ${build-directory} + ${build-directory}/classes . From e93254e8293efe6f88b1dbe203e18f6166f59775 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Thu, 5 May 2011 10:06:41 +0000 Subject: [PATCH 19/57] LUCENE-3073: make CompoundFileWriter public git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1099745 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/lucene/index/CompoundFileWriter.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/index/CompoundFileWriter.java b/lucene/src/java/org/apache/lucene/index/CompoundFileWriter.java index 9faf12dc992..a077a8f2716 100644 --- a/lucene/src/java/org/apache/lucene/index/CompoundFileWriter.java +++ b/lucene/src/java/org/apache/lucene/index/CompoundFileWriter.java @@ -46,8 +46,10 @@ import org.apache.lucene.util.IOUtils; * file. The {directory} that follows has that many entries. Each directory entry * contains a long pointer to the start of this file's data section, and a String * with that file's name. + * + * @lucene.internal */ -final class CompoundFileWriter { +public final class CompoundFileWriter { private static final class FileEntry { /** source file */ @@ -136,8 +138,7 @@ final class CompoundFileWriter { /** Merge files with the extensions added up to now. * All files with these extensions are combined sequentially into the - * compound stream. After successful merge, the source files - * are deleted. + * compound stream. * @throws IllegalStateException if close() had been called before or * if no file has been added to this object */ From 6af8928c95a11b9b6d74b368bf61583abd3ffd34 Mon Sep 17 00:00:00 2001 From: Steven Rowe Date: Thu, 5 May 2011 16:32:50 +0000 Subject: [PATCH 20/57] Compilation of the Solr-core module under the Maven build has been broken since SOLR-2378 was committed on April 14th (the Google Guava dependency was declared with test, but SOLR-2378 uses it in non-test classes). The fix: remove the test scope declaration on the dependency, so that it is also a non-test dependency. git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1099865 13f79535-47bb-0310-9956-ffa450edef68 --- dev-tools/maven/solr/src/pom.xml.template | 1 - 1 file changed, 1 deletion(-) diff --git a/dev-tools/maven/solr/src/pom.xml.template b/dev-tools/maven/solr/src/pom.xml.template index 85ddb316d66..b659a01383c 100644 --- a/dev-tools/maven/solr/src/pom.xml.template +++ b/dev-tools/maven/solr/src/pom.xml.template @@ -159,7 +159,6 @@ com.google.guava guava - test junit From 96878534a0397f3ed91794731af69545729b480a Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Thu, 5 May 2011 23:30:05 +0000 Subject: [PATCH 21/57] LUCENE-3071: Add ReversePathHierarchyTokenizer and enable skip on PathHierarchyTokenizer git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1099999 13f79535-47bb-0310-9956-ffa450edef68 --- .../analysis/path/PathHierarchyTokenizer.java | 121 ++++++++---- .../path/ReversePathHierarchyTokenizer.java | 173 ++++++++++++++++++ .../path/TestPathHierarchyTokenizer.java | 66 +++++++ .../TestReversePathHierarchyTokenizer.java | 157 ++++++++++++++++ .../PathHierarchyTokenizerFactory.java | 18 +- 5 files changed, 494 insertions(+), 41 deletions(-) create mode 100644 modules/analysis/common/src/java/org/apache/lucene/analysis/path/ReversePathHierarchyTokenizer.java create mode 100644 modules/analysis/common/src/test/org/apache/lucene/analysis/path/TestReversePathHierarchyTokenizer.java diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/path/PathHierarchyTokenizer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/path/PathHierarchyTokenizer.java index b0cd8d60cfc..608c386625d 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/path/PathHierarchyTokenizer.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/path/PathHierarchyTokenizer.java @@ -25,57 +25,71 @@ import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; /** - * + * * Take something like: - * + * *
- *  /soemthing/something/else
+ *  /something/something/else
  * 
- * + * * and make: - * + * *
- *  /soemthing
- *  /soemthing/something
- *  /soemthing/something/else
+ *  /something
+ *  /something/something
+ *  /something/something/else
  * 
- * */ public class PathHierarchyTokenizer extends Tokenizer { public PathHierarchyTokenizer(Reader input) { - this(input, DEFAULT_BUFFER_SIZE, DEFAULT_DELIMITER); + this(input, DEFAULT_BUFFER_SIZE, DEFAULT_DELIMITER, DEFAULT_DELIMITER, DEFAULT_SKIP); + } + + public PathHierarchyTokenizer(Reader input, int skip) { + this(input, DEFAULT_BUFFER_SIZE, DEFAULT_DELIMITER, DEFAULT_DELIMITER, skip); } public PathHierarchyTokenizer(Reader input, int bufferSize, char delimiter) { - this(input, bufferSize, delimiter, delimiter); + this(input, bufferSize, delimiter, delimiter, DEFAULT_SKIP); } public PathHierarchyTokenizer(Reader input, char delimiter, char replacement) { - this(input, DEFAULT_BUFFER_SIZE, delimiter, replacement); + this(input, DEFAULT_BUFFER_SIZE, delimiter, replacement, DEFAULT_SKIP); } - public PathHierarchyTokenizer(Reader input, int bufferSize, char delimiter, char replacement) { + public PathHierarchyTokenizer(Reader input, char delimiter, char replacement, int skip) { + this(input, DEFAULT_BUFFER_SIZE, delimiter, replacement, skip); + } + + public PathHierarchyTokenizer(Reader input, int bufferSize, char delimiter, char replacement, int skip) { super(input); termAtt.resizeBuffer(bufferSize); + this.delimiter = delimiter; this.replacement = replacement; - endDelimiter = false; + this.skip = skip; resultToken = new StringBuilder(bufferSize); } - + private static final int DEFAULT_BUFFER_SIZE = 1024; public static final char DEFAULT_DELIMITER = '/'; + public static final int DEFAULT_SKIP = 0; + private final char delimiter; private final char replacement; - + private final int skip; + private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class); private final OffsetAttribute offsetAtt = addAttribute(OffsetAttribute.class); private final PositionIncrementAttribute posAtt = addAttribute(PositionIncrementAttribute.class); + private int startPosition = 0; private int finalOffset = 0; - private boolean endDelimiter; + private int skipped = 0; + private boolean endDelimiter = false; private StringBuilder resultToken; + @Override public final boolean incrementToken() throws IOException { clearAttributes(); @@ -97,43 +111,69 @@ public class PathHierarchyTokenizer extends Tokenizer { while (true) { int c = input.read(); - if( c < 0 ) { - length += resultToken.length(); - termAtt.setLength(length); - finalOffset = correctOffset(length); - offsetAtt.setOffset(correctOffset(0), finalOffset); - if( added ){ - resultToken.setLength(0); - resultToken.append(termAtt.buffer(), 0, length); - } - return added; - } - added = true; - if( c == delimiter ) { - if( length > 0 ){ - endDelimiter = true; - break; + if( c < 0 ){ + if( skipped > skip ) { + length += resultToken.length(); + termAtt.setLength(length); + finalOffset = correctOffset(startPosition + length); + offsetAtt.setOffset(correctOffset(startPosition), finalOffset); + if( added ){ + resultToken.setLength(0); + resultToken.append(termAtt.buffer(), 0, length); + } + return added; } else{ - termAtt.append(replacement); + finalOffset = correctOffset(startPosition + length); + return false; + } + } + if( !added ){ + added = true; + skipped++; + if( skipped > skip ){ + termAtt.append(c == delimiter ? replacement : (char)c); length++; } + else { + startPosition++; + } } else { - termAtt.append((char)c); - length++; + if( c == delimiter ){ + if( skipped > skip ){ + endDelimiter = true; + break; + } + skipped++; + if( skipped > skip ){ + termAtt.append(replacement); + length++; + } + else { + startPosition++; + } + } + else { + if( skipped > skip ){ + termAtt.append((char)c); + length++; + } + else { + startPosition++; + } + } } } - length += resultToken.length(); termAtt.setLength(length); - finalOffset = correctOffset(length); - offsetAtt.setOffset(correctOffset(0), finalOffset); + finalOffset = correctOffset(startPosition + length); + offsetAtt.setOffset(correctOffset(startPosition), finalOffset); resultToken.setLength(0); resultToken.append(termAtt.buffer(), 0, length); return true; } - + @Override public final void end() { // set final offset @@ -146,5 +186,6 @@ public class PathHierarchyTokenizer extends Tokenizer { resultToken.setLength(0); finalOffset = 0; endDelimiter = false; + skipped = 0; } } diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/path/ReversePathHierarchyTokenizer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/path/ReversePathHierarchyTokenizer.java new file mode 100644 index 00000000000..07aa11fbbaf --- /dev/null +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/path/ReversePathHierarchyTokenizer.java @@ -0,0 +1,173 @@ +package org.apache.lucene.analysis.path; +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + +import org.apache.lucene.analysis.Tokenizer; +import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; +import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; + +/** + * + * Take something like: + * + *
+ * www.site.co.uk
+ * 
+ * + * and make: + * + *
+ * www.site.co.uk
+ * site.co.uk
+ * co.uk
+ * uk
+ * 
+ * + */ +public class ReversePathHierarchyTokenizer extends Tokenizer { + + public ReversePathHierarchyTokenizer(Reader input) { + this(input, DEFAULT_BUFFER_SIZE, DEFAULT_DELIMITER, DEFAULT_DELIMITER, DEFAULT_SKIP); + } + + public ReversePathHierarchyTokenizer(Reader input, int skip) { + this(input, DEFAULT_BUFFER_SIZE, DEFAULT_DELIMITER, DEFAULT_DELIMITER, skip); + } + + public ReversePathHierarchyTokenizer(Reader input, int bufferSize, char delimiter) { + this(input, bufferSize, delimiter, delimiter, DEFAULT_SKIP); + } + + public ReversePathHierarchyTokenizer(Reader input, char delimiter, char replacement) { + this(input, DEFAULT_BUFFER_SIZE, delimiter, replacement, DEFAULT_SKIP); + } + + public ReversePathHierarchyTokenizer(Reader input, int bufferSize, char delimiter, char replacement) { + this(input, bufferSize, delimiter, replacement, DEFAULT_SKIP); + } + + public ReversePathHierarchyTokenizer(Reader input, char delimiter, int skip) { + this(input, DEFAULT_BUFFER_SIZE, delimiter, delimiter, skip); + } + + public ReversePathHierarchyTokenizer(Reader input, char delimiter, char replacement, int skip) { + this(input, DEFAULT_BUFFER_SIZE, delimiter, replacement, skip); + } + + public ReversePathHierarchyTokenizer(Reader input, int bufferSize, char delimiter, char replacement, int skip) { + super(input); + termAtt.resizeBuffer(bufferSize); + this.delimiter = delimiter; + this.replacement = replacement; + this.skip = skip; + resultToken = new StringBuilder(bufferSize); + resultTokenBuffer = new char[bufferSize]; + delimiterPositions = new ArrayList(bufferSize/10); + } + + private static final int DEFAULT_BUFFER_SIZE = 1024; + public static final char DEFAULT_DELIMITER = '/'; + public static final int DEFAULT_SKIP = 0; + + private final char delimiter; + private final char replacement; + private final int skip; + + private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class); + private final OffsetAttribute offsetAtt = addAttribute(OffsetAttribute.class); + private final PositionIncrementAttribute posAtt = addAttribute(PositionIncrementAttribute.class); + + private int endPosition = 0; + private int finalOffset = 0; + private int skipped = 0; + private StringBuilder resultToken; + + private List delimiterPositions; + private int delimitersCount = -1; + private char[] resultTokenBuffer; + + @Override + public final boolean incrementToken() throws IOException { + clearAttributes(); + if(delimitersCount == -1){ + int length = 0; + delimiterPositions.add(0); + while (true) { + int c = input.read(); + if( c < 0 ) { + break; + } + length++; + if( c == delimiter ) { + delimiterPositions.add(length); + resultToken.append(replacement); + } + else{ + resultToken.append((char)c); + } + } + delimitersCount = delimiterPositions.size(); + if( delimiterPositions.get(delimitersCount-1) < length ){ + delimiterPositions.add(length); + delimitersCount++; + } + if( resultTokenBuffer.length < resultToken.length() ){ + resultTokenBuffer = new char[resultToken.length()]; + } + resultToken.getChars(0, resultToken.length(), resultTokenBuffer, 0); + resultToken.setLength(0); + endPosition = delimiterPositions.get(delimitersCount-1 - skip); + finalOffset = correctOffset(length); + posAtt.setPositionIncrement(1); + } + else{ + posAtt.setPositionIncrement(0); + } + + while( skipped < delimitersCount-skip-1 ){ + int start = delimiterPositions.get(skipped); + termAtt.copyBuffer(resultTokenBuffer, start, endPosition - start); + offsetAtt.setOffset(correctOffset(start), correctOffset(endPosition)); + skipped++; + return true; + } + + return false; + } + + @Override + public final void end() { + // set final offset + offsetAtt.setOffset(finalOffset, finalOffset); + } + + @Override + public void reset(Reader input) throws IOException { + super.reset(input); + resultToken.setLength(0); + finalOffset = 0; + skipped = 0; + delimitersCount = -1; + delimiterPositions.clear(); + } +} diff --git a/modules/analysis/common/src/test/org/apache/lucene/analysis/path/TestPathHierarchyTokenizer.java b/modules/analysis/common/src/test/org/apache/lucene/analysis/path/TestPathHierarchyTokenizer.java index cb0adc9e474..9cc50735965 100644 --- a/modules/analysis/common/src/test/org/apache/lucene/analysis/path/TestPathHierarchyTokenizer.java +++ b/modules/analysis/common/src/test/org/apache/lucene/analysis/path/TestPathHierarchyTokenizer.java @@ -127,4 +127,70 @@ public class TestPathHierarchyTokenizer extends BaseTokenStreamTestCase { new int[]{1, 0, 0, 0}, path.length()); } + + public void testBasicSkip() throws Exception { + String path = "/a/b/c"; + PathHierarchyTokenizer t = new PathHierarchyTokenizer( new StringReader(path), 1 ); + assertTokenStreamContents(t, + new String[]{"/b", "/b/c"}, + new int[]{2, 2}, + new int[]{4, 6}, + new int[]{1, 0}, + path.length()); + } + + public void testEndOfDelimiterSkip() throws Exception { + String path = "/a/b/c/"; + PathHierarchyTokenizer t = new PathHierarchyTokenizer( new StringReader(path), 1 ); + assertTokenStreamContents(t, + new String[]{"/b", "/b/c", "/b/c/"}, + new int[]{2, 2, 2}, + new int[]{4, 6, 7}, + new int[]{1, 0, 0}, + path.length()); + } + + public void testStartOfCharSkip() throws Exception { + String path = "a/b/c"; + PathHierarchyTokenizer t = new PathHierarchyTokenizer( new StringReader(path), 1 ); + assertTokenStreamContents(t, + new String[]{"/b", "/b/c"}, + new int[]{1, 1}, + new int[]{3, 5}, + new int[]{1, 0}, + path.length()); + } + + public void testStartOfCharEndOfDelimiterSkip() throws Exception { + String path = "a/b/c/"; + PathHierarchyTokenizer t = new PathHierarchyTokenizer( new StringReader(path), 1 ); + assertTokenStreamContents(t, + new String[]{"/b", "/b/c", "/b/c/"}, + new int[]{1, 1, 1}, + new int[]{3, 5, 6}, + new int[]{1, 0, 0}, + path.length()); + } + + public void testOnlyDelimiterSkip() throws Exception { + String path = "/"; + PathHierarchyTokenizer t = new PathHierarchyTokenizer( new StringReader(path), 1 ); + assertTokenStreamContents(t, + new String[]{}, + new int[]{}, + new int[]{}, + new int[]{}, + path.length()); + } + + public void testOnlyDelimitersSkip() throws Exception { + String path = "//"; + PathHierarchyTokenizer t = new PathHierarchyTokenizer( new StringReader(path), 1 ); + assertTokenStreamContents(t, + new String[]{"/"}, + new int[]{1}, + new int[]{2}, + new int[]{1}, + path.length()); + } } diff --git a/modules/analysis/common/src/test/org/apache/lucene/analysis/path/TestReversePathHierarchyTokenizer.java b/modules/analysis/common/src/test/org/apache/lucene/analysis/path/TestReversePathHierarchyTokenizer.java new file mode 100644 index 00000000000..a881be03ea3 --- /dev/null +++ b/modules/analysis/common/src/test/org/apache/lucene/analysis/path/TestReversePathHierarchyTokenizer.java @@ -0,0 +1,157 @@ +package org.apache.lucene.analysis.path; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.StringReader; + +import org.apache.lucene.analysis.BaseTokenStreamTestCase; + +public class TestReversePathHierarchyTokenizer extends BaseTokenStreamTestCase { + + public void testBasicReverse() throws Exception { + String path = "/a/b/c"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path) ); + assertTokenStreamContents(t, + new String[]{"/a/b/c", "a/b/c", "b/c", "c"}, + new int[]{0, 1, 3, 5}, + new int[]{6, 6, 6, 6}, + new int[]{1, 0, 0, 0}, + path.length()); + } + + public void testEndOfDelimiterReverse() throws Exception { + String path = "/a/b/c/"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path) ); + assertTokenStreamContents(t, + new String[]{"/a/b/c/", "a/b/c/", "b/c/", "c/"}, + new int[]{0, 1, 3, 5}, + new int[]{7, 7, 7, 7}, + new int[]{1, 0, 0, 0}, + path.length()); + } + + public void testStartOfCharReverse() throws Exception { + String path = "a/b/c"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path) ); + assertTokenStreamContents(t, + new String[]{"a/b/c", "b/c", "c"}, + new int[]{0, 2, 4}, + new int[]{5, 5, 5}, + new int[]{1, 0, 0}, + path.length()); + } + + public void testStartOfCharEndOfDelimiterReverse() throws Exception { + String path = "a/b/c/"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path) ); + assertTokenStreamContents(t, + new String[]{"a/b/c/", "b/c/", "c/"}, + new int[]{0, 2, 4}, + new int[]{6, 6, 6}, + new int[]{1, 0, 0}, + path.length()); + } + + public void testOnlyDelimiterReverse() throws Exception { + String path = "/"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path) ); + assertTokenStreamContents(t, + new String[]{"/"}, + new int[]{0}, + new int[]{1}, + new int[]{1}, + path.length()); + } + + public void testOnlyDelimitersReverse() throws Exception { + String path = "//"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path) ); + assertTokenStreamContents(t, + new String[]{"//", "/"}, + new int[]{0, 1}, + new int[]{2, 2}, + new int[]{1, 0}, + path.length()); + } + + public void testEndOfDelimiterReverseSkip() throws Exception { + String path = "/a/b/c/"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path), 1 ); + assertTokenStreamContents(t, + new String[]{"/a/b/", "a/b/", "b/"}, + new int[]{0, 1, 3}, + new int[]{5, 5, 5}, + new int[]{1, 0, 0}, + path.length()); + } + + public void testStartOfCharReverseSkip() throws Exception { + String path = "a/b/c"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path), 1 ); + assertTokenStreamContents(t, + new String[]{"a/b/", "b/"}, + new int[]{0, 2}, + new int[]{4, 4}, + new int[]{1, 0}, + path.length()); + } + + public void testStartOfCharEndOfDelimiterReverseSkip() throws Exception { + String path = "a/b/c/"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path), 1 ); + assertTokenStreamContents(t, + new String[]{"a/b/", "b/"}, + new int[]{0, 2}, + new int[]{4, 4}, + new int[]{1, 0}, + path.length()); + } + + public void testOnlyDelimiterReverseSkip() throws Exception { + String path = "/"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path), 1 ); + assertTokenStreamContents(t, + new String[]{}, + new int[]{}, + new int[]{}, + new int[]{}, + path.length()); + } + + public void testOnlyDelimitersReverseSkip() throws Exception { + String path = "//"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path), 1 ); + assertTokenStreamContents(t, + new String[]{"/"}, + new int[]{0}, + new int[]{1}, + new int[]{1}, + path.length()); + } + + public void testReverseSkip2() throws Exception { + String path = "/a/b/c/"; + ReversePathHierarchyTokenizer t = new ReversePathHierarchyTokenizer( new StringReader(path), 2 ); + assertTokenStreamContents(t, + new String[]{"/a/", "a/"}, + new int[]{0, 1}, + new int[]{3, 3}, + new int[]{1, 0}, + path.length()); + } +} diff --git a/solr/src/java/org/apache/solr/analysis/PathHierarchyTokenizerFactory.java b/solr/src/java/org/apache/solr/analysis/PathHierarchyTokenizerFactory.java index c93db874ec7..35ad58d4f9f 100644 --- a/solr/src/java/org/apache/solr/analysis/PathHierarchyTokenizerFactory.java +++ b/solr/src/java/org/apache/solr/analysis/PathHierarchyTokenizerFactory.java @@ -21,6 +21,7 @@ import java.util.Map; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.path.PathHierarchyTokenizer; +import org.apache.lucene.analysis.path.ReversePathHierarchyTokenizer; /** @@ -37,6 +38,8 @@ public class PathHierarchyTokenizerFactory extends BaseTokenizerFactory { private char delimiter; private char replacement; + private boolean reverse = false; + private int skip = PathHierarchyTokenizer.DEFAULT_SKIP; /** * Require a configured pattern @@ -70,10 +73,23 @@ public class PathHierarchyTokenizerFactory extends BaseTokenizerFactory { else{ replacement = delimiter; } + + v = args.get( "reverse" ); + if( v != null ){ + reverse = "true".equals( v ); + } + + v = args.get( "skip" ); + if( v != null ){ + skip = Integer.parseInt( v ); + } } public Tokenizer create(Reader input) { - return new PathHierarchyTokenizer(input, delimiter, replacement); + if( reverse ) { + return new ReversePathHierarchyTokenizer(input, delimiter, replacement, skip); + } + return new PathHierarchyTokenizer(input, delimiter, replacement, skip); } } From 826b1d32bd1455decf81cffdd5a054dcf4cf4412 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Fri, 6 May 2011 06:46:31 +0000 Subject: [PATCH 22/57] added missing synchronization to flushAllThread to check and set DWPT flushPending atomically git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1100103 13f79535-47bb-0310-9956-ffa450edef68 --- .../index/DocumentsWriterFlushControl.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/index/DocumentsWriterFlushControl.java b/lucene/src/java/org/apache/lucene/index/DocumentsWriterFlushControl.java index 443df5139ca..932b3d29b36 100644 --- a/lucene/src/java/org/apache/lucene/index/DocumentsWriterFlushControl.java +++ b/lucene/src/java/org/apache/lucene/index/DocumentsWriterFlushControl.java @@ -122,13 +122,13 @@ public final class DocumentsWriterFlushControl { // is super important since we can not address more than 2048 MB per DWPT setFlushPending(perThread); if (fullFlush) { - DocumentsWriterPerThread toBlock = internalTryCheckOutForFlush(perThread, false); + DocumentsWriterPerThread toBlock = internalTryCheckOutForFlush(perThread); assert toBlock != null; blockedFlushes.add(toBlock); } } } - final DocumentsWriterPerThread flushingDWPT = tryCheckoutForFlush(perThread, false); + final DocumentsWriterPerThread flushingDWPT = tryCheckoutForFlush(perThread); healthiness.updateStalled(this); return flushingDWPT; } @@ -189,18 +189,15 @@ public final class DocumentsWriterFlushControl { } synchronized DocumentsWriterPerThread tryCheckoutForFlush( - ThreadState perThread, boolean setPending) { + ThreadState perThread) { if (fullFlush) { return null; } - return internalTryCheckOutForFlush(perThread, setPending); + return internalTryCheckOutForFlush(perThread); } private DocumentsWriterPerThread internalTryCheckOutForFlush( - ThreadState perThread, boolean setPending) { - if (setPending && !perThread.flushPending) { - setFlushPending(perThread); - } + ThreadState perThread) { if (perThread.flushPending) { // We are pending so all memory is already moved to flushBytes if (perThread.tryLock()) { @@ -245,7 +242,7 @@ public final class DocumentsWriterFlushControl { while (allActiveThreads.hasNext() && numPending > 0) { ThreadState next = allActiveThreads.next(); if (next.flushPending) { - final DocumentsWriterPerThread dwpt = tryCheckoutForFlush(next, false); + final DocumentsWriterPerThread dwpt = tryCheckoutForFlush(next); if (dwpt != null) { return dwpt; } @@ -330,7 +327,12 @@ public final class DocumentsWriterFlushControl { } if (next.perThread.getNumDocsInRAM() > 0 ) { final DocumentsWriterPerThread dwpt = next.perThread; // just for assert - final DocumentsWriterPerThread flushingDWPT = internalTryCheckOutForFlush(next, true); + synchronized (this) { + if (!next.flushPending) { + setFlushPending(next); + } + } + final DocumentsWriterPerThread flushingDWPT = internalTryCheckOutForFlush(next); assert flushingDWPT != null : "DWPT must never be null here since we hold the lock and it holds documents"; assert dwpt == flushingDWPT : "flushControl returned different DWPT"; toFlush.add(flushingDWPT); From 2f75783026ba6a135a6d0b8c9744129b9d2bf099 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Fri, 6 May 2011 11:42:24 +0000 Subject: [PATCH 23/57] LUCENE-3076: add -Dtests.codecprovider git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1100175 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/common-build.xml | 3 ++ .../lucene/index/codecs/CodecProvider.java | 5 ++ .../apache/lucene/util/LuceneTestCase.java | 48 ++++++++++++++----- solr/build.xml | 1 + solr/common-build.xml | 1 + solr/contrib/analysis-extras/build.xml | 1 + solr/contrib/clustering/build.xml | 1 + solr/contrib/dataimporthandler/build.xml | 2 + solr/contrib/extraction/build.xml | 1 + solr/contrib/uima/build.xml | 1 + 10 files changed, 51 insertions(+), 13 deletions(-) diff --git a/lucene/common-build.xml b/lucene/common-build.xml index f8db3369b21..c6bdb1627aa 100644 --- a/lucene/common-build.xml +++ b/lucene/common-build.xml @@ -73,6 +73,7 @@ + @@ -499,6 +500,8 @@ + + diff --git a/lucene/src/java/org/apache/lucene/index/codecs/CodecProvider.java b/lucene/src/java/org/apache/lucene/index/codecs/CodecProvider.java index 921a8e6db62..04f8c591f7a 100644 --- a/lucene/src/java/org/apache/lucene/index/codecs/CodecProvider.java +++ b/lucene/src/java/org/apache/lucene/index/codecs/CodecProvider.java @@ -71,6 +71,11 @@ public class CodecProvider { } } } + + /** @lucene.internal */ + public synchronized Set listAll() { + return codecs.keySet(); + } public Collection getAllExtensions() { return knownExtensions; diff --git a/lucene/src/test-framework/org/apache/lucene/util/LuceneTestCase.java b/lucene/src/test-framework/org/apache/lucene/util/LuceneTestCase.java index 5888a1c008c..7e95cffacd9 100644 --- a/lucene/src/test-framework/org/apache/lucene/util/LuceneTestCase.java +++ b/lucene/src/test-framework/org/apache/lucene/util/LuceneTestCase.java @@ -137,6 +137,8 @@ public abstract class LuceneTestCase extends Assert { // tests) /** Gets the codec to run tests with. */ public static final String TEST_CODEC = System.getProperty("tests.codec", "randomPerField"); + /** Gets the codecprovider to run tests with */ + public static final String TEST_CODECPROVIDER = System.getProperty("tests.codecprovider", "random"); /** Gets the locale to run tests with */ public static final String TEST_LOCALE = System.getProperty("tests.locale", "random"); /** Gets the timezone to run tests with */ @@ -329,15 +331,38 @@ public abstract class LuceneTestCase extends Assert { tempDirs.clear(); stores = Collections.synchronizedMap(new IdentityHashMap()); savedCodecProvider = CodecProvider.getDefault(); - if ("randomPerField".equals(TEST_CODEC)) { - if (random.nextInt(4) == 0) { // preflex-only setup - codec = installTestCodecs("PreFlex", CodecProvider.getDefault()); - } else { // per-field setup - CodecProvider.setDefault(new RandomCodecProvider(random)); + if ("random".equals(TEST_CODECPROVIDER)) { + if ("randomPerField".equals(TEST_CODEC)) { + if (random.nextInt(4) == 0) { // preflex-only setup + codec = installTestCodecs("PreFlex", CodecProvider.getDefault()); + } else { // per-field setup + CodecProvider.setDefault(new RandomCodecProvider(random)); + codec = installTestCodecs(TEST_CODEC, CodecProvider.getDefault()); + } + } else { // ordinary setup codec = installTestCodecs(TEST_CODEC, CodecProvider.getDefault()); } - } else { // ordinary setup - codec = installTestCodecs(TEST_CODEC, CodecProvider.getDefault()); + } else { + // someone specified their own codecprovider by class + try { + Class cpClazz = Class.forName(TEST_CODECPROVIDER).asSubclass(CodecProvider.class); + CodecProvider cp = cpClazz.newInstance(); + String codecName; + if (TEST_CODEC.startsWith("random")) { // TODO: somehow do random per-field?! + Set codecSet = cp.listAll(); + String availableCodecs[] = codecSet.toArray(new String[codecSet.size()]); + codecName = availableCodecs[random.nextInt(availableCodecs.length)]; + } else { + codecName = TEST_CODEC; + } + + codec = cp.lookup(codecName); + cp.setDefaultFieldCodec(codecName); + CodecProvider.setDefault(cp); + } catch (Exception e) { + System.err.println("Could not instantiate CodecProvider: " + TEST_CODECPROVIDER); + throw new RuntimeException(e); + } } savedLocale = Locale.getDefault(); locale = TEST_LOCALE.equals("random") ? randomLocale(random) : localeForName(TEST_LOCALE); @@ -360,16 +385,13 @@ public abstract class LuceneTestCase extends Assert { String codecDescription; CodecProvider cp = CodecProvider.getDefault(); - if ("randomPerField".equals(TEST_CODEC)) { - if (cp instanceof RandomCodecProvider) - codecDescription = cp.toString(); - else - codecDescription = "PreFlex"; + if ("randomPerField".equals(TEST_CODEC) && cp instanceof RandomCodecProvider) { + codecDescription = cp.toString(); } else { codecDescription = codec.toString(); } - if (CodecProvider.getDefault() == savedCodecProvider) + if ("random".equals(TEST_CODECPROVIDER) && CodecProvider.getDefault() == savedCodecProvider) removeTestCodecs(codec, CodecProvider.getDefault()); CodecProvider.setDefault(savedCodecProvider); Locale.setDefault(savedLocale); diff --git a/solr/build.xml b/solr/build.xml index 80e66fd984a..de7ef217bee 100644 --- a/solr/build.xml +++ b/solr/build.xml @@ -450,6 +450,7 @@ > + diff --git a/solr/common-build.xml b/solr/common-build.xml index 861ff237062..a57b4074e25 100644 --- a/solr/common-build.xml +++ b/solr/common-build.xml @@ -61,6 +61,7 @@ + diff --git a/solr/contrib/analysis-extras/build.xml b/solr/contrib/analysis-extras/build.xml index 9cc5aa217bc..6ec8ecdbaa8 100644 --- a/solr/contrib/analysis-extras/build.xml +++ b/solr/contrib/analysis-extras/build.xml @@ -146,6 +146,7 @@ > + diff --git a/solr/contrib/clustering/build.xml b/solr/contrib/clustering/build.xml index aee297e3b8f..9a0c67eaa2f 100644 --- a/solr/contrib/clustering/build.xml +++ b/solr/contrib/clustering/build.xml @@ -118,6 +118,7 @@ > + diff --git a/solr/contrib/dataimporthandler/build.xml b/solr/contrib/dataimporthandler/build.xml index bd6ea50a2e2..79a0524fcc7 100644 --- a/solr/contrib/dataimporthandler/build.xml +++ b/solr/contrib/dataimporthandler/build.xml @@ -171,6 +171,7 @@ + @@ -231,6 +232,7 @@ > + diff --git a/solr/contrib/extraction/build.xml b/solr/contrib/extraction/build.xml index 01aa60e7485..50dcb4983d5 100644 --- a/solr/contrib/extraction/build.xml +++ b/solr/contrib/extraction/build.xml @@ -115,6 +115,7 @@ > + diff --git a/solr/contrib/uima/build.xml b/solr/contrib/uima/build.xml index 631f8a8c413..16c7de67844 100644 --- a/solr/contrib/uima/build.xml +++ b/solr/contrib/uima/build.xml @@ -114,6 +114,7 @@ > + From e555950a3e665962a8c6da031f660f6c24913e3e Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Fri, 6 May 2011 14:45:57 +0000 Subject: [PATCH 24/57] LUCENE-3078: Generics police imposition git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1100239 13f79535-47bb-0310-9956-ffa450edef68 --- .../index/DocumentsWriterDeleteQueue.java | 50 +++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java b/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java index 486c12659f7..0f39c45282d 100644 --- a/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java +++ b/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java @@ -63,9 +63,9 @@ import org.apache.lucene.search.Query; */ final class DocumentsWriterDeleteQueue { - private volatile Node tail; + private volatile Node tail; - private static final AtomicReferenceFieldUpdater tailUpdater = AtomicReferenceFieldUpdater + private static final AtomicReferenceFieldUpdater tailUpdater = AtomicReferenceFieldUpdater .newUpdater(DocumentsWriterDeleteQueue.class, Node.class, "tail"); private final DeleteSlice globalSlice; @@ -90,7 +90,7 @@ final class DocumentsWriterDeleteQueue { * we use a sentinel instance as our initial tail. No slice will ever try to * apply this tail since the head is always omitted. */ - tail = new Node(null); // sentinel + tail = new Node(null); // sentinel globalSlice = new DeleteSlice(tail); } @@ -126,14 +126,14 @@ final class DocumentsWriterDeleteQueue { // we can do it just every n times or so? } - void add(Node item) { + void add(Node item) { /* * this non-blocking / 'wait-free' linked list add was inspired by Apache * Harmony's ConcurrentLinkedQueue Implementation. */ while (true) { - final Node currentTail = this.tail; - final Node tailNext = currentTail.next; + final Node currentTail = this.tail; + final Node tailNext = currentTail.next; if (tail == currentTail) { if (tailNext != null) { /* @@ -196,7 +196,7 @@ final class DocumentsWriterDeleteQueue { * deletes in the queue and reset the global slice to let the GC prune the * queue. */ - final Node currentTail = tail; // take the current tail make this local any + final Node currentTail = tail; // take the current tail make this local any // Changes after this call are applied later // and not relevant here if (callerSlice != null) { @@ -232,10 +232,10 @@ final class DocumentsWriterDeleteQueue { static class DeleteSlice { // No need to be volatile, slices are thread captive (only accessed by one thread)! - Node sliceHead; // we don't apply this one - Node sliceTail; + Node sliceHead; // we don't apply this one + Node sliceTail; - DeleteSlice(Node currentTail) { + DeleteSlice(Node currentTail) { assert currentTail != null; /* * Initially this is a 0 length slice pointing to the 'current' tail of @@ -256,7 +256,7 @@ final class DocumentsWriterDeleteQueue { * tail in this slice are not equal then there will be at least one more * non-null node in the slice! */ - Node current = sliceHead; + Node current = sliceHead; do { current = current.next; assert current != null : "slice property violated between the head on the tail must not be a null node"; @@ -290,7 +290,7 @@ final class DocumentsWriterDeleteQueue { void clear() { globalBufferLock.lock(); try { - final Node currentTail = tail; + final Node currentTail = tail; globalSlice.sliceHead = globalSlice.sliceTail = currentTail; globalBufferedDeletes.clear(); } finally { @@ -298,27 +298,27 @@ final class DocumentsWriterDeleteQueue { } } - private static class Node { - volatile Node next; - final Object item; + private static class Node { + volatile Node next; + final T item; - private Node(Object item) { + Node(T item) { this.item = item; } - static final AtomicReferenceFieldUpdater nextUpdater = AtomicReferenceFieldUpdater + static final AtomicReferenceFieldUpdater nextUpdater = AtomicReferenceFieldUpdater .newUpdater(Node.class, Node.class, "next"); void apply(BufferedDeletes bufferedDeletes, int docIDUpto) { assert false : "sentinel item must never be applied"; } - boolean casNext(Node cmp, Node val) { + boolean casNext(Node cmp, Node val) { return nextUpdater.compareAndSet(this, cmp, val); } } - private static final class TermNode extends Node { + private static final class TermNode extends Node { TermNode(Term term) { super(term); @@ -326,33 +326,31 @@ final class DocumentsWriterDeleteQueue { @Override void apply(BufferedDeletes bufferedDeletes, int docIDUpto) { - bufferedDeletes.addTerm((Term) item, docIDUpto); + bufferedDeletes.addTerm(item, docIDUpto); } } - private static final class QueryArrayNode extends Node { + private static final class QueryArrayNode extends Node { QueryArrayNode(Query[] query) { super(query); } @Override void apply(BufferedDeletes bufferedDeletes, int docIDUpto) { - final Query[] queries = (Query[]) item; - for (Query query : queries) { + for (Query query : item) { bufferedDeletes.addQuery(query, docIDUpto); } } } - private static final class TermArrayNode extends Node { + private static final class TermArrayNode extends Node { TermArrayNode(Term[] term) { super(term); } @Override void apply(BufferedDeletes bufferedDeletes, int docIDUpto) { - final Term[] terms = (Term[]) item; - for (Term term : terms) { + for (Term term : item) { bufferedDeletes.addTerm(term, docIDUpto); } } From 78e553d270fd5f628dc1c0533d74833c6027e03c Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Fri, 6 May 2011 17:26:10 +0000 Subject: [PATCH 25/57] LUCENE-3078: one more Generics Police ticket git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1100291 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/lucene/index/DocumentsWriterDeleteQueue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java b/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java index 0f39c45282d..dc41fee97b2 100644 --- a/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java +++ b/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java @@ -359,7 +359,7 @@ final class DocumentsWriterDeleteQueue { private boolean forceApplyGlobalSlice() { globalBufferLock.lock(); - final Node currentTail = tail; + final Node currentTail = tail; try { if (globalSlice.sliceTail != currentTail) { globalSlice.sliceTail = currentTail; From 6b819e1bdee748b1cdfc5c363ae382ed50ac7026 Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Fri, 6 May 2011 18:06:00 +0000 Subject: [PATCH 26/57] Fix some minor unchecked warnings only visible with Eclipse compiler, also suppress raw warning git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1100305 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/lucene/index/DocumentsWriterDeleteQueue.java | 2 ++ .../java/org/apache/lucene/util/automaton/fst/FSTEnum.java | 4 ++-- .../java/org/apache/lucene/util/automaton/fst/NodeHash.java | 2 +- .../org/apache/lucene/util/automaton/fst/PairOutputs.java | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java b/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java index dc41fee97b2..85d2550a066 100644 --- a/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java +++ b/lucene/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java @@ -65,6 +65,7 @@ final class DocumentsWriterDeleteQueue { private volatile Node tail; + @SuppressWarnings("rawtypes") private static final AtomicReferenceFieldUpdater tailUpdater = AtomicReferenceFieldUpdater .newUpdater(DocumentsWriterDeleteQueue.class, Node.class, "tail"); @@ -306,6 +307,7 @@ final class DocumentsWriterDeleteQueue { this.item = item; } + @SuppressWarnings("rawtypes") static final AtomicReferenceFieldUpdater nextUpdater = AtomicReferenceFieldUpdater .newUpdater(Node.class, Node.class, "next"); diff --git a/lucene/src/java/org/apache/lucene/util/automaton/fst/FSTEnum.java b/lucene/src/java/org/apache/lucene/util/automaton/fst/FSTEnum.java index 77484164c01..db1b7ddee12 100644 --- a/lucene/src/java/org/apache/lucene/util/automaton/fst/FSTEnum.java +++ b/lucene/src/java/org/apache/lucene/util/automaton/fst/FSTEnum.java @@ -140,7 +140,7 @@ abstract class FSTEnum { // Arcs are fixed array -- use binary search to find // the target. - final FST.BytesReader in = fst.getBytesReader(0); + final FST.BytesReader in = fst.getBytesReader(0); int low = arc.arcIdx; int high = arc.numArcs-1; int mid = 0; @@ -278,7 +278,7 @@ abstract class FSTEnum { // Arcs are fixed array -- use binary search to find // the target. - final FST.BytesReader in = fst.getBytesReader(0); + final FST.BytesReader in = fst.getBytesReader(0); int low = arc.arcIdx; int high = arc.numArcs-1; int mid = 0; diff --git a/lucene/src/java/org/apache/lucene/util/automaton/fst/NodeHash.java b/lucene/src/java/org/apache/lucene/util/automaton/fst/NodeHash.java index 02719d81a6e..dde6409fc9a 100644 --- a/lucene/src/java/org/apache/lucene/util/automaton/fst/NodeHash.java +++ b/lucene/src/java/org/apache/lucene/util/automaton/fst/NodeHash.java @@ -40,7 +40,7 @@ final class NodeHash { return false; } for(int arcUpto=0;arcUpto arc = node.arcs[arcUpto]; if (arc.label != scratchArc.label || !arc.output.equals(scratchArc.output) || ((Builder.CompiledNode) arc.target).address != scratchArc.target || diff --git a/lucene/src/java/org/apache/lucene/util/automaton/fst/PairOutputs.java b/lucene/src/java/org/apache/lucene/util/automaton/fst/PairOutputs.java index fc8aa6691f3..7b6ead92a91 100644 --- a/lucene/src/java/org/apache/lucene/util/automaton/fst/PairOutputs.java +++ b/lucene/src/java/org/apache/lucene/util/automaton/fst/PairOutputs.java @@ -43,7 +43,7 @@ public class PairOutputs extends Outputs> { this.output2 = output2; } - @Override @SuppressWarnings("unchecked") + @Override @SuppressWarnings("rawtypes") public boolean equals(Object other) { if (other == this) { return true; From 2507c42b3c07b2c40d013d38ef7bd579aa730630 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Fri, 6 May 2011 18:16:14 +0000 Subject: [PATCH 27/57] remove dead code git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1100310 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/src/java/org/apache/lucene/search/HitQueue.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/search/HitQueue.java b/lucene/src/java/org/apache/lucene/search/HitQueue.java index 15e2052568c..e5ce5bcbc7a 100644 --- a/lucene/src/java/org/apache/lucene/search/HitQueue.java +++ b/lucene/src/java/org/apache/lucene/search/HitQueue.java @@ -21,8 +21,6 @@ import org.apache.lucene.util.PriorityQueue; final class HitQueue extends PriorityQueue { - private boolean prePopulate; - /** * Creates a new instance with size elements. If * prePopulate is set to true, the queue will pre-populate itself From 77691f17d07a390a5f39a5a269a273fc1a910e62 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Fri, 6 May 2011 18:57:39 +0000 Subject: [PATCH 28/57] remove dead code git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1100329 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/search/FuzzyLikeThisQuery.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lucene/contrib/queries/src/java/org/apache/lucene/search/FuzzyLikeThisQuery.java b/lucene/contrib/queries/src/java/org/apache/lucene/search/FuzzyLikeThisQuery.java index 0e42f56e9cd..113329abc4f 100644 --- a/lucene/contrib/queries/src/java/org/apache/lucene/search/FuzzyLikeThisQuery.java +++ b/lucene/contrib/queries/src/java/org/apache/lucene/search/FuzzyLikeThisQuery.java @@ -213,17 +213,15 @@ public class FuzzyLikeThisQuery extends Query BoostAttribute boostAtt = fe.attributes().addAttribute(BoostAttribute.class); while ((possibleMatch = fe.next()) != null) { - if (possibleMatch!=null) { - numVariants++; - totalVariantDocFreqs+=fe.docFreq(); - float score=boostAtt.getBoost(); - if (variantsQ.size() < MAX_VARIANTS_PER_TERM || score > minScore){ - ScoreTerm st=new ScoreTerm(new Term(startTerm.field(), new BytesRef(possibleMatch)),score,startTerm); - variantsQ.insertWithOverflow(st); - minScore = variantsQ.top().score; // maintain minScore - } - maxBoostAtt.setMaxNonCompetitiveBoost(variantsQ.size() >= MAX_VARIANTS_PER_TERM ? minScore : Float.NEGATIVE_INFINITY); + numVariants++; + totalVariantDocFreqs+=fe.docFreq(); + float score=boostAtt.getBoost(); + if (variantsQ.size() < MAX_VARIANTS_PER_TERM || score > minScore){ + ScoreTerm st=new ScoreTerm(new Term(startTerm.field(), new BytesRef(possibleMatch)),score,startTerm); + variantsQ.insertWithOverflow(st); + minScore = variantsQ.top().score; // maintain minScore } + maxBoostAtt.setMaxNonCompetitiveBoost(variantsQ.size() >= MAX_VARIANTS_PER_TERM ? minScore : Float.NEGATIVE_INFINITY); } if(numVariants>0) From 3a0d3e01bd5b79f1f13561d3c6b7d91c7536cbd8 Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Fri, 6 May 2011 22:25:31 +0000 Subject: [PATCH 29/57] fix false test failure (force docid-preserving merging) git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1100408 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/lucene/search/TestTimeLimitingCollector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucene/src/test/org/apache/lucene/search/TestTimeLimitingCollector.java b/lucene/src/test/org/apache/lucene/search/TestTimeLimitingCollector.java index 5be8753df0b..67d9333d6e1 100644 --- a/lucene/src/test/org/apache/lucene/search/TestTimeLimitingCollector.java +++ b/lucene/src/test/org/apache/lucene/search/TestTimeLimitingCollector.java @@ -75,7 +75,7 @@ public class TestTimeLimitingCollector extends LuceneTestCase { "blueberry pizza", }; directory = newDirectory(); - RandomIndexWriter iw = new RandomIndexWriter(random, directory); + RandomIndexWriter iw = new RandomIndexWriter(random, directory, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMergePolicy(newLogMergePolicy())); for (int i=0; i Date: Sat, 7 May 2011 03:23:00 +0000 Subject: [PATCH 30/57] SOLR-2436: fix mapping definition git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1100435 13f79535-47bb-0310-9956-ffa450edef68 --- .../SolrUIMAConfigurationReader.java | 15 +++-- .../processor/UIMAUpdateRequestProcessor.java | 2 +- .../UIMAUpdateRequestProcessorTest.java | 21 +++++++ .../resources/solr-uima/conf/solrconfig.xml | 60 +++++++++++++++---- 4 files changed, 80 insertions(+), 18 deletions(-) diff --git a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfigurationReader.java b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfigurationReader.java index 00e6aca3288..f540a6417f0 100644 --- a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfigurationReader.java +++ b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfigurationReader.java @@ -68,12 +68,17 @@ public class SolrUIMAConfigurationReader { NamedList fieldMappings = (NamedList) args.get("fieldMappings"); /* iterate over UIMA types */ for (int i = 0; i < fieldMappings.size(); i++) { - NamedList mapping = (NamedList) fieldMappings.get("mapping", i); - String typeName = (String) mapping.get("type"); - String featureName = (String) mapping.get("feature"); - String mappedFieldName = (String) mapping.get("field"); + NamedList type = (NamedList) fieldMappings.get("type", i); + String typeName = (String)type.get("name"); + Map subMap = new HashMap(); - subMap.put(featureName, mappedFieldName); + /* iterate over mapping definitions */ + for(int j = 0; j < type.size() - 1; j++){ + NamedList mapping = (NamedList) type.get("mapping", j + 1); + String featureName = (String) mapping.get("feature"); + String mappedFieldName = (String) mapping.get("field"); + subMap.put(featureName, mappedFieldName); + } map.put(typeName, subMap); } return map; diff --git a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessor.java b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessor.java index 8b3cb547d67..6994a5e3522 100644 --- a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessor.java +++ b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessor.java @@ -39,7 +39,7 @@ import org.apache.uima.resource.ResourceInitializationException; */ public class UIMAUpdateRequestProcessor extends UpdateRequestProcessor { - private SolrUIMAConfiguration solrUIMAConfiguration; + SolrUIMAConfiguration solrUIMAConfiguration; private AEProvider aeProvider; diff --git a/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessorTest.java b/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessorTest.java index 392afcf1ffc..0e2d5147215 100644 --- a/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessorTest.java +++ b/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessorTest.java @@ -33,6 +33,7 @@ import org.apache.solr.core.SolrCore; import org.apache.solr.handler.XmlUpdateRequestHandler; import org.apache.solr.request.SolrQueryRequestBase; import org.apache.solr.response.SolrQueryResponse; +import org.apache.solr.update.processor.UpdateRequestProcessor; import org.apache.solr.update.processor.UpdateRequestProcessorChain; import org.junit.Before; import org.junit.BeforeClass; @@ -66,6 +67,26 @@ public class UIMAUpdateRequestProcessorTest extends SolrTestCaseJ4 { UIMAUpdateRequestProcessorFactory factory = (UIMAUpdateRequestProcessorFactory) chained .getFactories()[0]; assertNotNull(factory); + UpdateRequestProcessor processor = factory.getInstance(req(), null, null); + assertTrue(processor instanceof UIMAUpdateRequestProcessor); + } + + @Test + public void testMultiMap() { + SolrCore core = h.getCore(); + UpdateRequestProcessorChain chained = core.getUpdateProcessingChain("uima-multi-map"); + assertNotNull(chained); + UIMAUpdateRequestProcessorFactory factory = (UIMAUpdateRequestProcessorFactory) chained + .getFactories()[0]; + assertNotNull(factory); + UpdateRequestProcessor processor = factory.getInstance(req(), null, null); + assertTrue(processor instanceof UIMAUpdateRequestProcessor); + SolrUIMAConfiguration conf = ((UIMAUpdateRequestProcessor)processor).solrUIMAConfiguration; + Map> map = conf.getTypesFeaturesFieldsMapping(); + Map subMap = map.get("a-type-which-can-have-multiple-features"); + assertEquals(2, subMap.size()); + assertEquals("1", subMap.get("A")); + assertEquals("2", subMap.get("B")); } @Test diff --git a/solr/contrib/uima/src/test/resources/solr-uima/conf/solrconfig.xml b/solr/contrib/uima/src/test/resources/solr-uima/conf/solrconfig.xml index 5ca6b8a335e..c0c8d17df4a 100644 --- a/solr/contrib/uima/src/test/resources/solr-uima/conf/solrconfig.xml +++ b/solr/contrib/uima/src/test/resources/solr-uima/conf/solrconfig.xml @@ -978,20 +978,26 @@ - - org.apache.uima.SentenceAnnotation - coveredText - sentence + + org.apache.uima.SentenceAnnotation + + coveredText + sentence + - - org.apache.solr.uima.ts.SentimentAnnotation - mood - sentiment + + org.apache.solr.uima.ts.SentimentAnnotation + + mood + sentiment + - - org.apache.solr.uima.ts.EntityAnnotation - coveredText - entity + + org.apache.solr.uima.ts.EntityAnnotation + + coveredText + entity + @@ -1000,6 +1006,36 @@ + + + + + 3 + + /TestAE.xml + + false + + text + + + + + a-type-which-can-have-multiple-features + + A + 1 + + + B + 2 + + + + + + + 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 literal 61955 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 - + Apache Lucene - Getting Started Guide @@ -268,15 +268,13 @@ may wish to skip sections. <li> <a href="demo.html">About the command-line Lucene demo and its usage</a>. This section - is intended for anyone who wants to use the command-line Lucene demo.</li> -<p></p> + is intended for anyone who wants to use the command-line Lucene demo.</li> <li> <a href="demo2.html">About the sources and implementation for the command-line Lucene demo</a>. This section walks through the implementation details (sources) of the - command-line Lucene demo. This section is intended for developers.</li> -<p></p> + command-line Lucene demo. This section is intended for developers.</li> </ul> </div> diff --git a/lucene/docs/gettingstarted.pdf b/lucene/docs/gettingstarted.pdf index d53b62c45cc7f1d2abc58d9cc266f312d47717d2..b95fccb9e9e44855fa77db988170e2bb0cf6cea4 100644 GIT binary patch literal 8496 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 KR5Y?OM*I(U@%s<} literal 3610 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 diff --git a/lucene/docs/index.html b/lucene/docs/index.html index a65f2775bae..7c6f8b7c133 100644 --- a/lucene/docs/index.html +++ b/lucene/docs/index.html @@ -3,7 +3,7 @@ <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta content="Apache Forrest" name="Generator"> -<meta name="Forrest-version" content="0.8"> +<meta name="Forrest-version" content="0.9"> <meta name="Forrest-skin-name" content="lucene"> <title>Lucene Java Documentation diff --git a/lucene/docs/index.pdf b/lucene/docs/index.pdf index 4e1a93a8647c070d395850abb307b2334cdab9ec..8e10347a7e3e399949f93b07ab1f4fce91766afc 100644 GIT binary patch literal 5933 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 A$^ZZW literal 1682 zcmb7_>sIPG6vw~kDS`-84>Y}y(h72?#e-686?;@h3j{2d7TYq*nGf?ob9u)}IE)7` zYu2&-lI-rCf3x>5JDEXSFNnMhGJpQ{_dlQr1sIMOpi+V8;kh01cvWx}J~- za=JNy0xtd+{Yx%(rmEriD6O{A4|i_Pddz*hxEE^29Lc8Q+F?nJ zjnz{&-%QtxEAF6hKI3uTSq1asdc~W{2JV~kUe~`XnEU;nnjHG$v4y*t)1EXs%veW$ zS+nDwC_B+X?`%+a5sv3v)LlC52B*wA{bf$Pb&8L9du}c8+V%WYx6r%Y5A6dfugvVR zQXkZ<^5{5jHe(yznC3V+?KY<4(Co~ua6U^X-?Rs>>hfhgS!%=8P(M=mieVfLxzeKl z)f7v=DEw9VQNOW==k1T3t-XTs4F5ztm=pvUZgxuBK^a-f0c^ z{wUXcydLIN;arV|PKFzfczfS`*vn^)+llnYhKp@Mw}dD=gnTD!;LZsp%Z*5oK#_j7 z06HU6&uxa!lo)}&iYUR7CczOv7Ky`kG$ApRzq_`=Afb^lWb9es2a6>-f6cH?T>-M! z<79(0lNSN%yGsV53{caJ3G;!dOZ;C+;!WH_GxVnbbpnd37tA5L@`6SXdoP9`dg|x& z@UGs4w2(m-qV^^`XzP$lS_udYe_~) z3{WdvGfDvJdD9r)Fq$kl+UY>jyU3QCxPCZih|wjsgzZEyj<#9=ZOYHOo-RWMkVQur zveL4V2wC3QNP?TRSacn@X^Rt^B&@&DK1!SAl1jB`>m<*~=I`Kt4e~i6Gax`w1j5S$ z6^vyJXK-s1MTJVU2L>-TNuqqewUyr41VQ}3R-*ZQ9V;l}I}M>E(OkUoQ|X_*wP{6q zKfLx61-zq?M6^wjh+ZG`xOu-5wqIn0VFFos==o;131pYd=D@~@8zq~}h_YG)nM}vj F!M_(V(DwiU diff --git a/lucene/docs/linkmap.html b/lucene/docs/linkmap.html index 22af04471f0..89d0b146fb6 100644 --- a/lucene/docs/linkmap.html +++ b/lucene/docs/linkmap.html @@ -3,7 +3,7 @@ - + Site Linkmap Table of Contents diff --git a/lucene/docs/linkmap.pdf b/lucene/docs/linkmap.pdf index 789b0ce98479e44e39cf098ed9eac2afc58d31e0..d05bc8e2b318bd499801d5247863fa11a0e2bf08 100644 GIT binary patch literal 15886 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 - + Apache Lucene - Lucene Contrib diff --git a/lucene/docs/lucene-contrib/index.pdf b/lucene/docs/lucene-contrib/index.pdf index d3c4c988f669a2826fc37ba141556e6aff430f80..1db16b319ee8399ba3965fb02b5e256dda068de3 100644 GIT binary patch literal 24607 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 XD56@~kh~?JUnm3(JNsEV37Y>0JhVmk literal 16055 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 BUPS-^ diff --git a/lucene/docs/queryparsersyntax.html b/lucene/docs/queryparsersyntax.html index 59222f6c2a0..fed92a4fa9c 100644 --- a/lucene/docs/queryparsersyntax.html +++ b/lucene/docs/queryparsersyntax.html @@ -3,7 +3,7 @@ <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta content="Apache Forrest" name="Generator"> -<meta name="Forrest-version" content="0.8"> +<meta name="Forrest-version" content="0.9"> <meta name="Forrest-skin-name" content="lucene"> <title> Apache Lucene - Query Parser Syntax diff --git a/lucene/docs/queryparsersyntax.pdf b/lucene/docs/queryparsersyntax.pdf index f2b045e82f5b5a47b90eb8dcb1f8bb90c8dd414f..79d61659ea2fb10638618d5eb446acdfc7e00912 100644 GIT binary patch literal 31192 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 literal 23058 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 Pp`1|Mk9fS%6@L7GX$3<- diff --git a/lucene/docs/scoring.html b/lucene/docs/scoring.html index c30ec4cd2d0..a0326be5388 100644 --- a/lucene/docs/scoring.html +++ b/lucene/docs/scoring.html @@ -3,7 +3,7 @@ <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta content="Apache Forrest" name="Generator"> -<meta name="Forrest-version" content="0.8"> +<meta name="Forrest-version" content="0.9"> <meta name="Forrest-skin-name" content="lucene"> <title> Apache Lucene - Scoring diff --git a/lucene/docs/scoring.pdf b/lucene/docs/scoring.pdf index 1855c61550e1c451769abb506dba6ba0a6815bbc..0fdf7919bd38b2805662105d5d4e6f74e129e25e 100644 GIT binary patch literal 24512 zcmd6PWmr^Q*D#8pf`ABuk^@po%?vPfx0H0F#1H~A0}Ne?bSa=nC?N<aBGL^ar68e{ zbV;WmA?0^w5c9s@$M^a3y<BrKv)9>Y)n04uwUhaZj2tI~i<f};Y4)=m0$vapgfzQO zAR<D*t!0C@gM-*4QKshBaFDXIIUE58ae_3>k&ZS9tBVBOn$Bj|;pS)%+rcvca>Ws8 z0n~H+{+68D6_5_x(a8ph0D-v#`G7joj&M^nP?j-81K4GRpkN3D%m?NN{tNO5vV)<l zU@+@N0x>ZHIKl$M3*Qf(Kp<{a5Dx+Hr3^<{p{+p>DDY4N1CX<^Lj#1l<?H~wGH`RG z1ssFJ2@R05Cvbc4FxFK|vyUREy^6o;O7!W_yB)UH8b=j~suZHQE<sM7zWnkI4kJuP z3nil-m2m>fHhLpXIx3GbG~kGO-u$uiGF=WRa_U$`i=6W#mF~-}i6iuzKDNnK?L$_} z-aX|wcXn^#y;9aYdE->79{JdGLvTcx)wSbCPOaeJ+To0%3JRnsw&ae+ANBeWZWm9s zMOjr&4EnNjsZ%_>7Uyg7-7<Yf2+ozb@afg9KBM!LZv;ejA264wy@@O4RcQlXZe!H< zgX+XMt#TN8ZN$S#1lOScBIjG2+Q#849|u_{A_UJ=heusIPdR;Js|;GrVtxy)7%0(* z{Fry%OBII07Cp!{<)mq0$7vqT2KD2daK{-{cyo2-J-6Q5cCr?dhPJl`TxXavgU_=V zX$D5bkcEx4x2sHtHM|8A^G945hkS@XuTL}Ph-2Blt55E3e?Fg4_=A9;0N9?>zM8Ge z*LXKEdebG=#NT)6ybS$T-G;7DJQ2=|40uuBc96ZzSsdf}BUdW+f?BU}<Aml{I}>|5 z(3N|cXw;8$Sg~gh4jL&PNw&SnJ+r)>OzbOt)vH~jdT4pl)NL(BAQ}ykHsMEDdSuAd zzit~xeK|Fi9JED$eBYUlf^?UuI+**etV~OWGDtbL$nZ5;FkZY=pu|>k!WK#0etKV7 zY)JnWX-BNy(Z>u_5<YY|Y?nwuCp|6LJC?l(8|87ow1&Nlk9)Y&?ziu)TdKVOnu5tU z(p+8!T6#vkZ6RUT;3zK$M^*xNPJ(&{m+a-S;+LeQI3%OEM<v;Uk2zd}jQWw^IU)n1 zB)?IVa_+8Q&NbF7eCHHW-dix#IrL5QQC@-LTsK>;9UDBN0VYnmadCy<t;A{nfY+zb zY6PJ{(ywXq1N81tf5gR;CcQ#)_XM-Fl)}-o67wk<Su{@r=Ta?a3}@KTROL8C(j_VC z)@QcQdK|w1KABN#@PgD1ui%=Rz==qI%Gx(8Pyu=_zmk{tP`F;Fm;BZ0?vIk{5s2T+ zB)xH(ROnF{n3Up`oK%z>(@9c>>^o=DkJ?D|-=RyVFAG(O%6x4|jxQ?<xuSfRu$lgB z!1$xsRGm~<+Eex8R~}}Gb!m68T_;#4RgtrO)cUS%1_#X{bpBx&mz-`&Vh8O^!3^nV zf$g*Sw^Gf+A(7{Nm1$Vc791@&UqIa%DHw3RG2ApGPw$yf56yfiQG??PGdoBzf#+$@ zGoE<Dk>0m1jH6M-0#}VhRD;>;wMPw5tSDU+S?T%8GsCBs!$}&}R$4y6x8%G?d`^f* zCNr>+g`a%xuOM~FlruHDLry@cRLM<}>CAetYCY=FjnY6pMG+YhH5%q>W_1NiCfLQB zObqr6i>wbBhZw6sF>mB7NE}7<m4~GeEXfQbtTpN>m-H?jV_PBDVeeu?Uouj6%Lvxx z)%vVu^eiq{FV#)PLE+PrGbV2oLUQWW4IXQyp|xfM-xor)`{V?*1f|^z9K%-eCgsUF z8iL2A$J9gFcG#@g%(eWVs=+nOx}3Y@=Je+Th@^Qk@H#YX9v335ZxvoV8yfoXa^dBq z%Mr~EXD`yGQoqBUnf(miHr;mK7S`s}R@1JYW9f!<vp>!4p2~91`qX{7tG`>WYxoII zmv>iZSIHCCCnKE_HgPuowjZxAyc5X&geJC+Y@u0t5G@!qJ=o*V*UEc=SJ!%}lcwWA z&-<R$&gS<|-wUO!Yb8EkOnvyYN_xkCBb`{gNku-TKzcg8%{-8xE+(oi%i=R61I_2W z=geHbUVf{b$D`3h-6Ozb(PQ)T$!(53rajv2s%=etA$$gWJp3H|5~5Fm9ChS%#({f* zxe?(JX5p}N&gVs;Iy}VSHhu(OwXGD)fnVS9{WZr{a`R@W3eS+eN8c$}0lyL?8$t~Y zYNdUPH&xLZ#MwciN+A`7A4aWwrZXnK&JG@F@SgJ)Cn0AAN3#BTy#_=3g1M4yYkTBF z#E`XjQ=l1{wWf8a`C4{PJZEol<3_*Hs?kVU_Owg8H^K_hR5D=h+L?5n-mIp!x_AH9 zt+ZROQ(H~nzk3OJm)G+NKdh0!+}`q`tCX<2V2+E>)aRbQTKxsD4__!LGn5jP!dlYY z8`rkhsHP*z=E@w6=8YdCPL;@%R3S86ja?%>Z|&fcc#|Z_$29q8KCyZ_E!l2m(qqDy zOPt$lXSH#8<07(tpuM8rvm<DnY*KU4X+*c3zptd*wYhy588C9ux6t>_SJ+qTBL+tX zZ%o~IBGL5n-c4`G^b|bFZb=fqRzKNVQ3jO4wbvVWD%Oam38!5H{5o!QET(S03a^U| z@TQMENkW)=()XMxnfmE>H8;wyz4431%Vn%$Y++oMiI-7)<dJqZjqFik+SMkvrn^lF z<~e4%jV7U;!DRK$P39A66N%%Ql-nGGWhjwau~dPvZN>>%_b@Jw9=!+ETU%!um>)39 zpLrJo3E>P`7EFDB-}d?ajmJewnWc71TuWq0$C1a8(aX);(`rm*EcaMNFT1D=CyB(5 zCuu~jYQ3b;B23EM&g^+ytxBjeki2nGl%+}(_kL8IgO&nm#>pLM5ziVlsNiiuXhC|* zgZqm{FlK@?d~oT$u>6V!-oEy(8}%~zCeVb5Sk0I<7Ji{kg(Sx$F!EYi->OOr>#Fx! zjmb@eTH|+yDTXhKuc04LH*afqJbj$)p*x?;WguGJh-|%C<X>cC>&sTi#lh`W#${=& z7Nzqp;ZfeY&%9yS*-+UAepsnp)<AGS+XsPCo287WD)dTj%#=zwO6-?MkW+~2t$VGy z_pW;PM;F3hyiK)h*LkZm)-yjaSVGID%hk?JKR}mX<#gO!{!Qe4;rk1fS4?%)OTu0# z<trJSH|jHnUnwe@^LD<xt`MQC;+bQ)n9<)`;a-uu@aaRRPNuf5!6qX2+H$K$&2}4p zT41PmoVVZ(9ZZgY!?$(2yi76eN#Sgr&zR5b&0t*b*2vaY&IC?)4k|m{dG*?>+LjSF z-_D^%yKH1;$$h$`K}<n(zKL6l>vfVrp0{5_7J6H48QUK(N=ql3Ga44`zW1JaF>;<x zjLNOBr0H?yglEh0CVi)<j+4=(Ti?l7A&<zCRi~04h~0CZo1OjGX<nt|vHT!J)G3F% z61ig6(YH43)&6jHb3xpFczrjIu#Ga(#KL%?{3Gg#(@UR}iQ_x;Lin`!!a+1a<=n!? zOXrjLy~aa#?se)`<t9~7pcdc1-i;cYSMNm*E0i)+y{Y&zqqCheUE+jjAJliE^e*|B z^u8)|Ct;J?hj%Z}cn%~gHYX~ya;^53u=!vft2q4YXP?R$hA*ZK{%taA7Y5{;SiD)e z#Z9){b`^VK;xik>*}od?y#3hcTI0401)mk>+c)~W+nJkqHLK>s*Y`{CW%P&7d%EXy zEluuMs{1;Pa?aa-t%!3a<0)ItTV@xJ^O^Z_?(?Um%y6}2AKXp<wH-{p`7K@imU+Uy zWuAuIiqg_jrcQ7R5GEPbFg{F8`F}}GwcJr~5Vr~(ZE9hPHpL{RK!%LQ0`*jsf6iKY zuvzPm^i)LL4al->;b@Q<+{y+a%D7xn!w9mm5M|WmQvs`>q~X>!3LcJdO%GKqa}Qf{ zK?_E4F%dT*H+z&lKn~<)Z-;Oaaua1V1u|y15bzrV=4KQlA`o%3uoTjek^5E$D2Xy! zqtPfKZf;jsS1wl`E~KLsH$+fSkQ)r;hC(@k8k|n<2(+miC&KB%cN8*kCv!&|6ee^3 zh6?o)DufdkmNb_+(w-Z5zzyNz;bsJ3Xq%cLozbF<SVX`RAz;AqZA2gjj5|aywSR^I z9AhEhMiOG*h9AEVB)+|OSnJzc*s%rD@%u|iM@P658W^;Eli2bAz-5XZ(_ke(Ky>&b zfQK8y^iR?r>hLGfp}y@=-*x$m0^CedfC9k(pa7u3gbob^GXN69jD9%5e4Jo@EeJ#i zEGUE>0ttb^BHVw}1(?IYu)M<m=Ix(q{;veHF#j$W%GuElt0xO{Znz!X9*#ge0kT2< zK{g9>A;9k8hx*clI~@MBv-zLo#ONESameAf_qcyT2mC~12BU}gB<;|LKkaNVjUi-b zim(!8bmO#uTberCp&1V?;P+AMLF@iR?Hei#weKV_lz&+JA*H_{dO+=eqVXHvf3h_! z3~*SiLcY7W*pCna1Se5OM<4(Y5&RjlAdv4N>Bk@$Gpg74$00K4M+|a%a8F+`W}x^? zb$jk8r^~(8ChxK;j^dWwXf3<eFp_v0(3!h;7)}PXSU1*)5k=47pNz~Lzk4B=@y2j< zF6B<-@vl|uW4<<Y0<unPn-SuoYY%CXRBro}R()yTdHH7Wby-eqvZ>O!CPegccRHab z^Hw2F0|LI4+xxFVd3+Zu9Y>ej&1((!CKp%T*(_N5J8h@crZ;@~mk~&@9B!3-YYG`r zn+I$<$?Lnb_z(^U2bb!>!j<8mMDcz9%*ox|r!M7U&tiu<%Uy_3o#|o7*)w>l)Rrkq z<6EiJ0b$UZyiUeFCiW`22E+-Z)$H8*4K!nfM5;cmy_|F2w523fL$%W*>9sDE&X;Ra ztPTZi3AcCEO_GEhgh;|ZE%|-88oP2mp9A@BoPCYng3m}lv!?pKxnaKK>z;08?|Od1 z(#$&L@Y>SN`_E_7)C|SHm}HRSYOlT}bdu*}9BJ=j+*o}(s~SUikI)Og5-Hqm7trzP z)|*oq`zv6_TNZhbdsfYb(fKrl%&?HOQ`3TyM>C&J)PbBjX?CN|->>()|FR;4da8vv zduzejNOi;?)_7w|#Hq(d{PlHxqjoiq$0O#}-3DUMQd5Y&I(#s3de)~~TGf-O{j7KS zMR6B$UfxQ5l`hvd-NTjkQ4*QwwV3*~U47kX0yt|oL7&m}eK!2c>X?Z2o)e}wsS3BZ zCktqU_TSELx9ap{FD!Y63+xq6rHoQn`b9~8uFIp9sS<s5w-Q-1@D3JYEPk5--_pMO z@iwT>o<GgV;JCd~$UD?M^PJW;dhW_|#g9(C7f_f#uFw^j>Lzilr&3C`e%3<9Ff4O6 zZtzmv6vD2Q%w^>{obU2*D%U0&5pcVfk5bD~f470|gW+V?*B&Qyeu$`1-@{@dopIhr zRE{##W}oN5Y;Xvya_G|)y7Dp&ke&!rAP-$6xc0-{wAkI{DA#R@j<R=D?3IisuDefq z;L3Eu1eDaZD--Mc6$G;-^IuaiDAc}?d#eKhNy%PJDnS)9zo;lUUdpchDWTP~`hjfg zr!y7-IS-;=-7gY-vMVz+$Dkw2Oi*{3C42qCvVAbYt3`biH@=?r7#~#BQM?<TF6fZm zvm0RRU_mZEb^*wxM^zGP=RXM=ujXW>Ipw0s^O*3Mx9xAwY*wCOztiwE-Tk6Cj@_Lb zMbLb~(Ad`aIl+uQ+PGtq?l_gR^gdC{y=d3Xxy?Fm*W8j!FS{e{L_8X)7d^`xd#%LK ze&S$nmcAhWFOru>O*!q&6>f-elo6QT)DdWz&!2N6YBIOBW`BV5cDp{gXG}>@`#p=& zZROO9ZO)PV;wzo59uvnn+3_B}RHV%w(c6}c?J}eNqQ9VrvtV~JNE~+N7V>n&<T7X5 zdi#Asa)PQH{ZTw8xk$bMB=KMh?Wt4Ma@PlMY74{UKjIL;q;))8)m|}g&NS&UbZ~J- zudi~E;ro=E`APNgC12(r;16`*kFr>i{-S~N&V9b4L-<tOe)fx8nG#)1ywn=T;8<tc zqmS<P_LSS&N=TQ*t~q)xzq6p;{qowwNNI=oiX$~{)4k9l5mPC*+FKocaU82}f*l^} z>u}bGGN#f<THI%5x!!l};mNa&>Ro21{aIw-P3)uRJN5GUXd>E1gx<bq_@r~{{q6f< z_08V)=gX_8YJ6l>j?m$)G$;lwIutgG4{w5=;B<(j?h=tL#xe(+DsykB?Y$(uon3GF zBu38Z3D}m$nW2As8FKHO9DW;pUmgou<uS?R)o{?6h_@@B)?lg>E_`a9bOG6@Eykq) zhi8xVVsQ<bl4`nCm}XS36IY?1``-5pF)(2}n)7^tn)$9oEPIM@opR;nrO}J(AC6ou zBjMvt>FMG*T0kHiEZ6nyR^WBD`!BEFT+rRO4(R1^H0je+D`9wAm>Zf$Z*ieo<6_x- zoc-F3>V5Sm(k|e$1}gT-@QlEOjt!l5_hHFi|E!&Oagb%MmHLdMp*G>nMKQ3tq535) z+ovL>?351A6}4qsw?+MK`acC(&w|&RPvl*<%S>;W>+|L5N-5-dYPPU+O8$s<h>0!C zWChQT>(m{y7u+MM&n6y9#GOo>tO<HH6g&PduDKHIc`~MpNW}X5EnkTLNuH62Xqnd3 z&sS_&aZvbVQijL5Jx%flQ$3Ds#Z-%ggjAyNX6yEGrfv@Qho2K**6jfqEvL)AY!1W) zGYLsay`gu1QWZL@q{n>RpMi-q?Q-865z;PkmKX8@v~wrSZ=^lHK)Vd;Tu@zdIi5+s zb?w?HSc2}Q*Q%+%K`+6U)#z3ATtR+v;fCwv`0RT0?y`7>3}>n2&*0}Ek5$yx?in2` z|M3398g~Ku21`-u`(T2MNFI3m<bZb=x>EYB7TF?8H``_9dio6icH#TtQrVaKE6ye= zKW2utPMtn-)<7NK(O(i>|Bf~7OT3tEh)en%*`ud5J4=+R)W>trWQj(^KYg9^L|81` zxPofAT7pSE;kkrZXXtcpU;T(_4BMu0d(#u`(YdlE&)WI-88gWzp4cXZWKP*oeY!;Y zeiZH#vR5`j5ZjV>^+D~m5~kHH%41I{u3Pz(&>iV;x=YpcAd&u=wLEARUok9&J+4no zxIvoct*B11z#eVgxx@`?1@O_UxX<8SJn{+Yr%`sV*l`dt;E#-1;4GdpPiCVB*GX2B zO0Ia_Z9L(+lV#pZ`;gK1-pR`_aFt|4hOoBX1gRHWbpw;9j3}pp;AvLS6EE{d9+l@s z=7m8?CkIWbb`3%so<0m+<Lw~Iqas}_Oivlp(~M#Jl;=0+r0$}0YUkO8yb1UgVXmWR zT#qv<Mj8bUErJFzi#Pw2Fv7KdM!Md}KNoFM21W)z>f1<vO2%()ct{Zte|u$&lJ6 z*G!7<yY1t`YB+TNkjH?(=P{UplLp)g>Fj6@cLE&@odD3mXzPlp6&zDR1#V$uDur|d z8Dd_90qX+%f>2}36Dd15+~OafXgS*0|Ko!zrj9_K3&NyQ*tG>|Bm#{|d_makN&~a5 za5w_QE<j*bDWH6Uu<t+&lNcZbECBuvJX~9WLinNIfrmp(5s@G18fH}a7wKA+zLL`b z>~!^x?hC=f)$rEUi&62jsW#E7^qnl`t{%aTHxv})>Vl;1=nP&R!BgPC@ynl3O0+p9 z`O<82V9$k8VFqtyTFAc!=Kk^Qdc$<sm9_vAVkgJB?!|^p<OS|EvSk<Xy;Fwcyz9O0 zcc=48KGoSR4)qKNb>EiP7<{LMoUHv?LxN}Db$@<#EyG&4hlZ=__V8jZB@)3sJP`D} zz(PyrZI?-OX#4fu&uQd=0;OyF)z;UB+9~P9UfBt@CD*Hp`@btRjAUQNSB)<AkK|M& z-*Lb%epUtEh;f5X(F!W}D;ck^GOe5IJ+yx|nOCf6cnm*citSuO?agG_L?)uDTNDY% z-BuO?zYm5x`qANxzSnP)&<YQ(lerDB5oI!P7^~G8$_)B_%^2Ebeg7mEIgol$vAw@h zH#_?})f=ADZ7IRUC7anqF%R)g&2tv7z^1q2$P_YX8`aiCMxIqgdU!s#4fTx)``Ty| zA~P2d<^QT4wBmSGK(gP*%s{lC#F)qXVxNzia6g-}z%g>|^5p>p)p{^4YY~+Xo%LqQ z$5Ypfk(rXRiPFCO-ZuTuS<de0N@c8EC2b2Tk3I72c3vIsDb-!Q_)iH-Z?3HKKeIeL ztCt%oA8+ukBwUAi#DwalboxjA)6+@km`vkBB&j~e_nsV#kzim)5%Y`5$e#AcZ_A?$ zByP*Q&+<YGard&Ek41;(?AlX%ccg>!=M4|e+hG%*K67~X=O$_iz)n2+B*M;f=jnB| z=9@rzh-*&}0nSWkzpMGO6DPx<QuA8%2bHJQ5|GZ6o~h5S>5?nm7P8AW>+hXS=}u7M z*UHq}lRsXQ9S!e$+G`K#5`sRqdwj{v242@mo6R<7^qza^3~xS8%IEe;bZol~H*Jxz zJ$E-nd9P&*UR53FNbeEd0`*Vtbsk*2p{W1fvF!})3k~xTJnmCY;^gCN^6wJ4HCMbd zBk%ifiN72SyG1AczFRbsq4)8lUB#gz7da#2%-ZYtrD>y;G)=hNJMMbB><E6H@iOyZ z>(lcWnNID?-;~?mB?!7J%|HFAdyo{zW0{c^k5S)BJVC!Q>-Ebg(V-^Joci(--Q?L} zh4rgjXD;g><2|z0>CnmTa%KG#VOSTX{;ecom(L%H@Fr<&(%H$E2Z)8k&kil?*MinA zwxGceQtUpH&o@Yc@**ifi>9^5X4p9{9aXw=_w=rw1q0ECK|GpbhF%wvDk_BT$SBLB zu>7|x+-I{%k6Z@lC2HAh7IfYf(<OWiJ7rI&qocf9roeV|?^V>m*|jHgVQsH(Y=nsQ z8^;}`7Hy^4w0og2;XkG!ZExNbIy>A_$eVAQwY1&%C`)xB@`d1J;VMPzMq4}nQo$Xj zv&du-`LgAPW8niVcoeJ;H<Yy3JT-{q&gxPTI!fmDrvw#F#b#wb@NJYlM`eAf#<qga zTq5*^!1B2`7M*>N^hi&KS}5;hiD)i~g}^jr8OPnbx0DPD%SA2>BxTHmFz{C9L>Os< zpL-5Hon-N(8R&WBmU{~|=N;-YBhW1wk;?d<#`s3RqRI22L7N2EuP^({I20aw#Lgt= zSQr<sJIp*ednr;So^5V4_wA|IwxprciqH+>=Pv|KSb52|pENdT3lGC<Cdwt!HN6q@ z_^}ixvx99T*Mx4%xpR0*dBt&IE^kltQYfm7>&<>L3=*_-QLkxU?8Sdk-pD3N#Lo6U zExmH)LmLsOk2=~|Hu=)HgUEV$+CGx%TEsilwFj4lX6Y$JMBiW0U41J1I^y(~IfEx_ zK2Me}5Gp1RZc-8kGQ)6f`$vi<r5ZH-Qgo#*&+lYiYSF@x{(72ApR>d5Eo{!Jp}Uvx zzO^v&Lm52PugNwM{Z<jJlAS?}JFC#C>3tCbE!IK__vIN&PJ~(Rg1vpz>r?h?#S7F1 z3n`0V8S^&;k*zJ7rj8s-gB9$1T=!LfmNI^p$~5lj#0g}XvG5ElsE331#$ajDg_(k# zBarqRUa6|wCHHmLn6J#JUJ73fMxSb3tfuNWRNy>z&-vA&;BD%7kE?D|^KxfoC)VV$ zlK96JZ`a6>9QVIYfz;Z930j_mhwg1h)rWMkh8TOdRr)Z!*igPW+7rd|8U0v1<`_}; z^ka=^W4wim&@++B%*j~=BWy(Hu2#}tUi3<B9o$h&;B+4eVf~1HCj~K&SW*uQU{T?3 zlS<N0dHtOBF53xptENbljzC|NhrN(ep9NXG^LUp_GT3nC!bk2jn@-l@_s{8;qp#BU z>T_K<E;U(}>mvCvm*IJVR)h1SE{OmW$XVrOy>}!ZV$F6lOvhPKCZ89;s*@EN8ym?r z7jKj%MsM%&vEMtsP}(Cq8MW0gDvs82U37D%p<`a1Z~$+5QCa1y+|EEl0#1l&Uwi%V zZAB0%F}!IhufQm>Sihn7De-G1BEpYu{ZUfK#3+vRC$l-bi&woCV0oNZxncEGn6mGN zV^CZGPH$D&c}ge82d*J;-YN7#eu1jPp#DPQkyRroKY9as>g$p823t~0Fa7I`Fyz<G z2>(~o5=<8HYg%$RGYt_C{E=)3eoIS!N;aUFbm=dWjT}8C<bVJs*_esLiO^YYf)Mq~ zQsTLUom)(uy%}qrNUeyzD2UkKBW8A#iAN`JC4e9*8Xw>Ck5rO-9N8WAU*YDykb7Ns zM0ZSp(u4VJgeI~#TYOmFWQ=v#BRh61N<d}rS$H#a!%>_AiX8H|nu{Pw2PT1*n{U<J zZVGkTZi(2g%q_h(wA8;dmGjl0$}m@qle;z4;*3mNp-FUeyX7`E$@t)TRfl$A$7y|? z`fX3=uA<m%5LiR)_C#YvP@<f%l+t~s(7jR|V<>m{9+OV<uC&YLZS@{^&**K)0@rH8 zhDDD}&k6E`u6N+(Fx;BpRUpY2^0JQKai_zRT!8yTF?B|{?yhirK!~%g&^_YSlKznJ zWQ>aR>Pz4DlDd!+d+Va&E_~<DEqhf}*mPM}ruAO6R%;;3@$QsMZd)YB571Jc15Go% zchKJk>715JN*Sh@PGkJc6GxJ7<Kxe`el4;7)iH*Z%U2Cdwf3bmk5O&d#oEiu>@~`Q ztA{jFH%Zss&5BHX8U5akop;Ty&Af2dBf2Oku(*&~F3!VSrDbPqH?K2E+td5J+1qlb z=RmJQZ+j1)mzYvGIlN~zQJt_RQ)V>k#p;QL&e)@bn_Zmg2|2-XwrTu2l|wHgdjjo< z?b;e52*tT;4aS&0;dQBg)E^N+aTbiK@eHDbUw@JI-r-WG8!}P!1X1_AxT#*KSLg7h zK2Y>>)#M{u?QUxR-K<uJe$BBChKRiv$}Ra1&^MZnOzWHMXE7rb;0daEDr()8LYGt2 z(=t-;%}NwZ#B<DLs#r$`CU?1!AbR4S_pJ3W_{8o!F+F<BJNDV+s}x*HT*-?nicbSS zi!K(GE|--CUn=RI29uX6zoYfIoKqE=Tg)}O{kV%c0X=)$Ua7u-Q(fiwtAu?cDyE&c z53PJ;o~U{xKQ7{27)nA5PebCOGi032ZPhK`2i=kgm~<5<*0O#n{+{*e#EiAwh>zGQ zvXx8MEFiQiu0fR-h>14Rn{c1#<ej;DYNj>4Gi|@rrVpH(BHq^XrK9_E)84tOS#IW> zn}mC{5$ye&#LSNz$8@L(P>f}C&zEQ`OGRm{b$Mv<5s9=$d<%w|*>+Jx_%*^}SHdXp zKe5>C1=)HxxJdMr53wtot>kLyaHY|Wp7Q&AOF*ZNG<R_pC1Ra*X_&~*_5xC0K0$6^ z4qW~LzEE@Jf-kpu3H);4O-T)nr>1X`rU-qH;@()+jbju0a6&shS(C}+NdtWnNza^N z8};S#sHhov!pLi4_{mSH(}$<}%8eiLrJfcfZ@z%aA&=Rw)2<VuO?DlW+u%vdY<DGA z?Cz@hs92%Z0HKbbH86+)zkP5YuAQ3iMD^%(hDf}s<88^~ior4_G$Bc=p4wh(muYie zF`b~?Ux?PW5pU`avXyrWd*wK$ULsomC7zS#m3(68{n1{7sL8pH=d5Wsd?{*4-Akh$ z@Escy7Gma8x+P$;b+-2X2ZkA@Th$)yZnpL}Q@n89Xs0_+`eW}3`)}4PJXw4-T|U5U znTKNZ5BPlB#pKTO@a|hMv<fv_&h!=Gphsksx2NT=<-HLKE<R06`PzDgVP&R;7D%n! zWA6xN&vGO{XWb>MBpgItPjM@r2$7DZkmE%Ph^I6pp(b9vU<r4sGyOQxL(Dm0DX$vg zXq|M^HT5Zn7Lh$^{2BD(a2JkO^*dKPMLrI{!V8oruDKxgaLoyQx#Z&!Hu}dLX5UDj z2@Ie~KXR8-s@Prq{Jfm%hO?<yvFDY{Hhbe!MUmY-4JI@neNLMxQh#}30|PcjXmNFq zE4RXFnq!Y$&onFNyScQN>1{!CmPO4c@3XVQ<B6!0fp`j+a#v@EUZ)R%v5$QD1|6d3 ze71GRR0+Z460z4S*DL%AE^Q?hJ-bPv=Hh0RHGQO>d`nS_M7$qoWmoXC?2BMIUsvv9 z-f2+}(q3vbDg|7!Ba?8yq$mEOSqT2g@rJ&lOJzNm-j0)mazk_d$F7ganjYiDJW3hK zxp<j{2D*7y4MIzbu1geRXDd!odn(@DR*Ze)s&xS;FHw`*MQ7q=w>W3t{ra-=HYsK$ zS-v;D6(5ybbzdKv^F%Yeqa&?Pc#kXObYZe%%gLf`*DS!Uq~p23lhV9l5a&#b$-5Wj z`O?vx71PHrw4UfcceXv=Dyy1)VmBczTE?0*oTbGpbJZYpKUc!qCeA8M&y?&-=bU&9 z-p$H?=#B-x_h|o@W(hF;>@VFhwwJ|D2*CKiPY6IUdlxalpSxr1^u~W)s)^7ah#o8^ z^&ZK+rcL)KCwg}5;oC$G`HPP=V&V3eNle7ADZD*Rs)#y*lAq6Yy~Tt$W(9j39Y}e4 zrgLZ-jT`ERyZeQ~&o}fE@!bB>ELTFZtR!Chl)Sj;;NBJkaWj~RPIcaPi|I{1ICuQ% zWk1I7W)ZiUTO%Wt)apayJEJN%zF&E|-LCM9KdZTVz4<k&nq>b3-M;r`dr(FD(j)hH zuE5u<-ghilOALML1a2vLzr(+}jDK!3w_@b$jm*~7UB;SI7fKCkl5#6X37_$rhlp_4 zJn&aMskaKc{EAn<b~m&wd%YmX(k&t2WH=Y0m768_ybO-@&9p%_N-=-9QMx|)gVuCy zQVLlw0VYYhSetU?FG-Qy;SUV+gq9&~kJirwPR&o=+9;ja=l;yZ75rp?1WiT7bb?lj zuYA5I+nwk+0^GE4o<Ef~t$jd1Hb~<rE}OQy!cz&8bak!fu!Sr4jtI9i++_$(uRBky z8b%on3bo?@ur+2%)%azuMGKeeQ^%d<M)KK0XE{OV*alN|NseatP2B}W;(1qfQorLQ zL9dJ0`}5dUUO^LrxH1BwHb%}n>KE?y2&KsBD5g=6rA-#U&MC?lrI*NmomyrxpUQmc z5=}4EW&WYhpe9%O{dLQfquG=mY?N*^R*kJCkKkybl5JJ1u<=PReyD-@^C>Cmw457n zJ8pM3oaB)dT4l8~e5zo2l0AgY<n%+fwb;gB=VLsSY$SVSPoc^mjo5|7h=;Yt;Y@sU zpS6O!2`*7J5f8s98+j@}zdU`CXHt5xkJKUZEJD&ds5Qp6p!<Qm7fao>9YgPzw37wb zWTW1WDNnV8+dA(@;yz*`xFDEsAm>AMolp3@fX#|Fd&!-V&gZ!D^VZfMVvbZ%vM;5F z+&f3EAt9d0`c+z(0tC@ybs^1&J`&Ht&W<Y)aW`V`M0Seg69&<J63~pDMdR7_LeCy> z@MW@(ajUnT9o{rFUp#(IR>$Awo^E%7jk-0FNpQCOt$LaG#E)`!YRr_XC_Qs4tW~9% z+rGBb)SuQeKO0AsfOG1$M(gpL9E&Jj7hF&+`NbC;F%2ku^BCzug`9};NRutGKu()T zy#e#by`LI(4B)nI>@YZ8BNWzPc6Il%UGtgOczJJ%^ZHJIcqNC=c;Zap-Zphd>{6`5 z70nd(ODQn!Z03@PFp`kEY1eruy#i~YX<#7jY{-Y0*Z?)5s({OnuBL!0*X4u@HWdOS z<!$0jj-13>Oc_kB_B&0G(`ps4LI`%}eoUk%HlFan<kVoSNpVO+D~F*~Ru_}7#xbh* zpp3_aOe$4Ej4{bAAL+!+I<6%yh*EHN8>GbsXjGc;#gSQ-UmUpIQSm|9v*}A0btNVI zt~!h-JG<mIQULP!rFZX@w?Q@8%PX@M5A463x;P@Fva^uTv{Mo*OBXD1HMG}H@{CM_ zw%VG3pq|m|+}p!C5dB0VsqxJty?h0hAIyroKqTrH!|Z&5bw2ezD)cH>-YaE$_$fmA zk|t$@VqF*gI!?qp6&>1DLM=hflgcGl(^Pe4X1F6quH+bh>{rVw-;`)dwrQo!o#`l+ z37Y86*WhlgQ&lX}nB+fepH>-mb^Vc8%EuQ^a?y7eFX8hJh&8(TER7Tr#O2Ep)uy=C zL<?4^cjw=_5!C3l>s|jgczGO$L~21tn>G4&?83TScvf<+VX5eIL*CQFHQn=99UQmZ zmK#hJgBKr=)tnDYFZ{C4e!-FC^HIAv^yZV@!l{rTsSXGJJy+_s^No=nEFEcmynAj? zxt+XDLGOAw0Slf-wDO*v;?1i_7^xXmNdd3iAa6f@ony*KLLJ3psybm&I`WD{s><Uz z!8AvGqx)PKXa=MzuT73Tw|FtFF&P^#=z}z^{wlz`wSzpzS8bpl(NTYnZt$7wWIL|5 zC2<H}pnJuHYe0Uq(SY0&+aOtCw8M)f0U^=SXI_~&&cTEueICYIVJF{eW+Xj<vkm2S zUgmo3|Kxc4;_Gp3i=*B=m#0!b<H!;Vmvs3&XeT6>TP1S!A@PwmTE`3jB7y3iIbvWG zzTaFe-N)hbR4ajr*!MQs-Oum=Vc*Y+%*HCLmKyZ=%4=HpRpwKz87Sr&&L_tD^pP!* zUl5jGP`M#U663tlT-+dikAm1am!FX+R^D*fp|wE|WFnV)D}Pg$(i^8P^TNU@|C^b& z<(|1o-_uTTNqwg2_RJ}&ifs~6V%z<e?rviEL+GbB!(VQmcJ!SXD>c}0y)Wv)^T=YJ z^|EkyAUsrWy5Nbc%NvwOjOlUhDB;RnRxWF`ecr%IiTC=2yxiet(PJ{p{O@AAx9qYh z#+=61Pi1K&W+t|MWtq}vj$>72eN|fFd+)eo5^`9xnF<OTU1;q=I<{9AZ&-Ci^?kgj z_)$rblhV^GtzpbRT_=lX@49~GuGNV!UW&|hw8rb<oW(5hI<=TVkBcejyEdtr{W%)? z4+M4t#=D{~K!gKHAr9u5s}{*)yZ0-epa`SeV~1u8s}1I-h;0heao$^M=S5Rcbme59 zEVo3+JBx3G%2OKd!$y~15zK33d%=fjGZw6qNEh^~GOTsA3R>m#RlSyDHH+}iI9K%Y ziIiE{vQP}09H%Y2rqEJYQRVx%AuAQRLel!iBzVf+$tSos#^;@?P<9f;JpG+R4_=d9 zPAcDpo+DNymj<&n#f&AKrB4|Yn-tBsXJ>oudsKb-oVdufRu(04uWZUUaQ~?Pm%fcZ zGa~4Z{U85_G9qlM^J_+QxI_X4^YLTEI9NmZDI+>q-;qQhkZ9~tlY@<P$~FjF0$@1^ zICf$Pf`Fl1U=SZvkV^o>2jSro6yyW(@q)QvAY<U12~YtuxdFx$q>zpl!0C{mAd(;` zc3TVqw*rV;kpQ!%bI8Syr1Ef;>2J7zfVp^oZ~=vILH~{m>}t=ST<~BxKg<sQS{J;6 zz`nB|T!0~fX8uYS2Px|xy5RXaNBw&)_#s?;z>dNnt->n+1+?=wobVj1y8X$?;qn<K zTmE}a_@F>L9NGpij0e!pUvY7;%=jl4Kd;yQJr_LCpDdJ@m*+1nln1-p^dD^Fzp_wX zz(aV!VDL}+fb#yOmGb<HmGb^qR>~vD``t=;LA+qzzqC@Gf3Z^D|H?{v_<4bLIJ6BO z0lvSqP~LyBP~QK_LV5W3ezH&=80;@Cl=ojOl=r`~P#zvWE`gtHgBQfZ3;Rne<^2~c z<vpB({%L&6i?Q6lm~Or|q~=7^6czYMSge8OF>aIbJ$>I*wl|N=`MvZ4O7o8AlIWdb zBt3EzdZNFlWTfqggrBJNiu>dXyi;_%mMc8Bj6;^B`Z(u(P42Gy%5@FRZ(4m7U=M0) z=882=_W7zOw(2v@`PJL`>$11~d}8vjTggsx!F<t9OW(+Twb=I5{wLo_tEHCho;oY~ z;p+Z9kByd?+(Mt!9qzS>>;mzsXBB0h>jQoH$<A)<6(uA?+Z^T#O<65w71ha06}ro= zzB@~qi6dW2tGsrWmUf0*E7ohi8XCI0IjQW_CFTwri&U=HEl=l)SFO#rB3-`<)p&bt zPPR79^H00p=kMKV+Mb&m%c<+#TG?uA2nrkUHL27us984Io9=7R?a}?*LYaGgZ~q>A zicq+cV?evTS6j@tWoWatXIgLR>T621g<SfpSB=E0*Tz5fRaci)Rr>6#@O}N9zj%3w zrhucG{vG4gp5#|YPoKT5hhJ{bmr$0_BUaCf(!5lqdD%Sd*^XQt!^v&?x;*#EeQ<YU zrExxSz9MXX7vbf@G8u-O)5MvxU?_Gk=)%2R@nz`7V%F7~j<Eb^?HQkkMU(f37F!c< z=f+HrT}dVexA-`;>sE<2@3T245kF{rr8!|UZ8KWPp>3Vmp*l>#r9;5V9*}si`Q7Eo z>yI6aHSqY!29;4fwXJykl!HbnTR%gx!GzJCV<lXr&b2v&2x%0x-@xg?j8Pa~$;DEY zTFzr7rw9Eix&sbBuZFIVA&O8X2Bn5MgE=}&I@zO^eu*a$ETv_mQ+|nr2(D7T+MJUJ z&Y^ydQ-xJ0atIek7xnym{EG?gS6p;b?WNdD14b$Q3{m`srHPz_trSa^gsugzhMuAL z*#}!MxfV1JJtF|n#UJ41!s7jnOXCAB1ApOC3PrdyMd-Q~Q1Ru}P$i0=d$1KKH4jxf z^5+h=erGdhx|`Hoe>^LvT}`bw=4Eg-$GVL7b&vAd<;+ZT@qQP??(CWYP2;D5b`cMv zs#niz5%~!64}uH$^HWEKZy5*Cem*fn+HoO8o_NCagzW0q6b_D#bn;*g0<DX9`F9D7 zdx8VC8neRH&!<6E;SZVx?m1lQ%u-H+Ml_=@bv{wfgx+dCb%`hIZ3;A|S@{yr6Xh%M zDbOSExuZWm*Kb0LB;pNHlyk0R=&)(B--BE-KfsxZ#mRes@!@Y6)3F%Iv{<qLoHwAw z66Xz5!a1)r65P!@3V$YXKKn}JrMr0q@MjtTZ*uT(EN>H98S3$JaH@N$Ek0@UK52x$ zY3#mfO1^2fzG-2;Y1zJMExu{<zG=8PX=FHQ7jV*ea5De)b0f2}L&dPfzD=T+hp;8Y zrUvPlQO0$S^XqIyYei7I7@tyvcX+&RAA+Pr!~5&U&N<5D;-rz=9;=<O_VLNdhVI0m zdB0>aAD_Lcty=Ms%KfeVH}?wEEYF+QXtg7oHs&9m6XTGwl^O_uxh3}2j1`|;{Ah3T zHPDdKpw^xMp@~ZL8z3J9?4p*lbYN_of6%d{ZXH?3Ik<@0qehfrK>a#PE~WcKB?l%P ze`vyG7?)rvom@vci#AZFw9b#9=B0$)geg+_QWvGDD=~lpe;o|wV<n@AAfVVXL=3PH zTS5EWw~o_Q*yyX=Kr<GkgK@WGSif^R@H?!-u^c#@F=`&;aDXWv!#W(mH^Vmv!7y7o zi9v2{_!IvJAQbzdhisB1$L+c8I+~5gh$qnrp1q!I#rbKnp0!%=lYV^9<L-BPbNlhO zGd(pukLZ2drsk&u&?NlQ;@(?LiHRhxtXwbH=TA0%ex0aQd|b?gJeT!c<-<y2HLx2- z;EJScZ;LrvKJjnK9H<!ptYFl<=;2puNZDUI@GWlqt4HckE`9qDx@H4W1c)D#h$6=l zgEGUM-;|Dx8!DKXL^)VK+JjfZP)by5f8wwmGcZx(1fq7xZVXY3jUH#0ECVX^#}GQD ziP}q+_bT+y9>lg|*w}_qHqeGxtQai=Sg~5hVm+`903Aaq-nWq9HHN4@j2b`y`4%-; z-YOZz-7f`mJD8fRTD&f?U+lWWolDdvdCiM1-+5qj*J=s2>|_7BWPg32$0>9D+(2FT z-UOwn=ydkP$4vXA2H&eSWu<#4SHOtD9|nB3mK-u0Gf8~P+g)~U-sdk_7B_jAY~Zv3 zTT3kRhOzcOsHCkl2L2z|8RnNgaFlZXm&n=}A`W7`|A2S#US>olS!UWwm%9*3h%$*v zt*qyxL2Z$rEnZKvEQ@NM4j076;Drts*desY(Ot0<`0o&+`5bQ4QX1>PIc?BZ^uSiI z_qtKGLr!CnQ16^kwo^`R5q>X~ku56cO%Y3Pf)RVE4l3uRL0Mq^#h&J~OaRX3^cZaG z3K(pQ!QZh>7$hU{`-@q1BgAeO2VMP&>MHhJo$A#IbH8ABw=N&)6j#1!r5iRDM7y2* zWiHvL=;Z{ixJmWi>dmj^Uf!D!ZkoQztabD?W0steTWNLl-UW`7RD;i1k6{$h>p~Mt zI%3!Bbac49gLwFPCf+v%*<(670>uB^zAg6lZY@KOPSnGWC4=LEC4-#&<+b*ch_WFf z<o6Eo&}e|Z3$Ve7{blnz8v&V(oo$^jXR}1?MIH(~49INLe17)3N(_ksZ7jt}cls4M z_R>5s%NZ0ro~g&~+FpCH7kZ#%C#;gG{#nJ2zo~cxi?0leZ-n-N87H@13wzIMXi=pj z=Y&CHQ8>_69**xCGeiY_3@KOCHs=MyOX!}XR)(gAtQt|>O{S+x1dWDDrkhX>AHt@o z+sE(UrY!OGs_}-6?4h0a$LbnBB?-Grnfc6>vQ8mot&OdZBi9Ck49WVr3g?sM3Qioi zPl_AGM$x3i(VhU86_}bD3gh@X2mVuziBdoL&-dtRxYS#3xD>m?H&%=)8O#j<RJ>{X z3ZvqyWIt4VkaIX;(gQ%nB-6}InTo8Ir~^it7z<enjjeB$d|9I!gr%PS7Pr4+{uEm= z>7!DKMTuZ{ZP`n3`yK+nCm-18L3R*5Fp&v}9@vbA{2-$_{R>h|vT&Fwuped$hcRix z;!>%N_rR1EYR?>9$nUb_7_@}HVQXL@7@iCZ%HG*u&_X@Wy%-eIE*_RV{P1ecp4Zi$ znA^J^U-nn$b~jd+Zcm)o9N}jVT8x0ni$iV`3_tg!T*c~kpYie_)`|f@573GHdj~LR z5DaLtgyNO`7{Wb~6<KCDJoN_9bBX)v_g=*a^&`+dHf$X+J=H&IpDQ)s@3QJbp6Z-R zTlp}oBLVOc&BNZxy%&pVGi2b^&}y3+;1rdcWF_}1CWn$M|H}y4G9cyNGPK%w1%r(5 zF2FRBxB+N>cTct-&3~+fl|Ka0&%HD-Xh#gJrTSCpk2JO0oxGc!WxxNzSIzxHjTMii z$7+-~LTs2$+@p}RW8%0;rGU@EwC`6R2T#}Ct*hMo?hekCQw3F%I$ZL(EA^`{)_76n zNvP4nPv~*9=)lV-Yv@t5X!pyDy^hZ(4+0z2L11e;3~aU7z-H^1GYZ7YqqdXGCj}Y| zzBm95TuE~TaA0n^6q^PE_lrkW%YZ0(=y`vl6FP{Kzo5g0UP5A2Xwj-8ZUV)#dz93p z<hGNK@c|O<sYkwJ6uWBvLa`<<-LQt1d0S%_$Us#}W}UpXDMsYWYB*<tMto~ZeVo25 zFRry*wc+>NKL_{pPrDyo^DZ(26Y{^zFIdls&<eDUz~wP1|Ha-*gwvM@H=C*7pbSg( zh7}qO5wZNypJKBoBP=RaN}_g@d@EY7S_BQS6vmX8_+xy#m=l{i{YTfvAX@^EVO*Q$ z?JD4g))W|PLB;+{)&%spgxH9DnAb1>0|{(C_AOl!ESltWZRutJ>{%57*o~u07?3MD zdbAiGCQ3lY^y>fx@1F-K*pUP#CphT5ua+iKE=>hgxQ`)B$`W;#rtVdgVSDcJSC#bv z?r&lUU5o7piUkK+Js+-G7JPBnNff`~=6IoR+O-CDp^ahJPQGc?`^$E^o3S7HTHWip zFPSTK-2;gOEfucIw*wzL*%O!K+TTWrWOImM##^zwUxW}U))gK2$Th2lQhTYE@8hhJ zUBw-bP-;~JOmM9o*tHQxU`Aw9B!do^#A@I_3A756$M{k!X-PoEq<th1_uLaNU<1JG z?^^mbo%}=XnDN`sYCl8}jPd*L=z*35(Epcye=ykk&zX~>IH%}BQIS1;=40_1p`FQv zuSaeSFi-u%^!nlKiXpJ!A2XFf0L9K|5MZZkH3+ctrNGz0)G`mIHc&dKf}JbVAiz#m z0bd7Iu+udf1m91T|CrhP|37_?o%MDCK@X$=j#7L-2Z5d1`DH#IJF$bAuI7dEeBW@$ z_w(%Fw;P-Iu(N0Xd543u#v9c-@ad{)_9?ljm-R};7b^Vkr0|{zdc}~gYOY}RTB^II z$z_3y{0uXXPtu|&^{w1t&1XL9QlQ)_ZW8KK(vQHn#_7X-L^sbt6bLJFG^|gjfEg5} z7^DP<8FEa;1i!vrji#?V*5xYxvC<(-)7GlYPPRZKP*-8Oa=t5ZiJ!<EM*Jv>N-xEp z&p_trB;vuDq$;_FA&)iP04_PN$2_DuNv$v+Jf7}1sM_O3=Td_kLzPa%G0JhqH`&=_ z@)scL^lxN^My6G*pjvEN6iBIN1<pI0(>E}g9SNK)wmy@}##pV!AOkTsf1~uJ4AGFk zkmJV9^s+}gHPyK@V%&4J-Qrzteh(+|V+TjR$!q+wnWy<lv+v6Amfdz*DXlldGiusT z?&Ps#2wE$%tDFoyvnSD#x<vw$I(8#O-Awl={h9Rkmsff>{YzY!#w@ep(}h{}$8&pJ zqVzqP%QsWs@U`?^xy`4#F#MF<-Nt*^xpG!k$NtjCd>=9**NE+i@P`-2S03G4U)~wT zH4QGWb%h3%h}*s%PkB?<`R>)t%A5+(MPD4!$*!nBy@dD2M$`ZQR{Y&)vDWyD(PC}! zz-R>ySAY0^nZ-T00!_=*47dpmX$dm_b`a<y0f_tCAtAnld060LGPoNW#CH%BK-`kR zvJ}?&#l%40)|If&zOU#UV1|Gc5oqis2AGQ#{t4|BN4N{HsD;IKNaUMC0z|&8Vf{qp zFhF6KNe+lWf85#jC))@3581{F0Xq~)&c+eAJ%R6F?jJaxWD1mE2V!A@firMM3I=Eb zVB?_5Pi*`=_xtT4IVcwdBxeJ+vv2~LA}l~MNONcGbpk(2eJI(1G7sV=mcZebs_)AD z5h#J>pl@;l6X}@S>EIwKB+?0uy`=7kz=x<01U{7MfY1SU454q!Pd`cW!<K&{!~@bs z01JvvXh0Hx4hRk0koWCkJdhmH(can4^q<5!pnWLTfwD0%5;$dsp?#qDAGBdV$ItIV z@`AJgYEm{<per`!XlF<Gzf(Gt>wwb1x&@ZfL3{s13G?hX+k|rQfz+Mhj_x37J5who zxYNJV!Sacb;egJeg#Z%$ZWmbV`GXD&By9~`;DAx2rj5OgovEV@+Wp_D{UpclW`Q-` z-|+MN!0rwlBK+P?oSYz8Hx%3v4N``?!0mpfcjy2I?R9852htt7q9o|sLeNiI{D;`V z3z9^kfCymY_OAqf^EcR`GamTcVd=o%AXrQJw)pcCWlXK#<mLtZP14Q^xUCUwZT}N- z*iRDtVFy3L2PSeKtZ>Q!Q4dr4ewz&j3@`$mtpx7G!8`?VE5Pks;Ak6jQ%)(QodxEZ zECRTL5!0mHx;6+&gp<u7;OFC$upe>ae@9Qt#vbm(se!aNMf^RnA2H*9N9?<Be^2U1 z)c7w+ajKcw**G|354Rp_?tfI}FCL7&bO>`c)(O}M@hwnuE7<^{*AN?hfUOglumi%L zX92zrfY{9=8X#=<tpPH|Tn=)$C*r$#{SZeQxa7zVX@vn`Dg8Jvdw9bQ=v$OMsGw|W z2DftpeTzvTZZ&7Loecsw(tFs29#m5SZteteYdgUYpZ{zx7{@#?a{_Lx;Q<$w0`%p0 zK(KFK3KaN2ShK<&-IarYVBg{`@B|8i9Yzf7Wu@ktz?Dme0A1jIByL4}KwnbdzNG=< z$8_kJ%>qa}q@yNqV-Os4KuzZ0k{JzoDbN8?Ku<qZ^`qs1c<5{oXdDc@2haeqK`vrc z3h3!u8G2BL9+r6y$~=c<-h(plVVUos%y(FZVawQd`rc5#gdnULNSb4E3t$foh+7`1 zg(TpX0U3U4er`Q|1CSsXSaOC5V3y<&&USXjKgoja*T09AzsJS{fdNbUe_;DrHQzQ* z{0(nVFbr6l{~a5)r~V7xuptiglcd1*3+SKNepuFF*!xGl{f-UFk6FI|gSTJ8@xSZs zcWe+~V+232aYpb@j6VY9|H$8gBma<=2WZ`Y(A{6Q#2?sr1pc92vHjp*w8Zb&p!}F^ zF~92$+qeB^Y~Nzl4@v*og0Y(u{u^w3m`ysr^M=jo|1-AV1?7YNlc3nJcZlp;s(sis zA9Vc(r60Y#n<Lzk01N_-5CB^>zWsq<e0;z@AxqE!3<}}JjB_x5AjEeVA4aLa!C?G= z5&QxJ3Yh-jHy8wyp8N`f3SiXwJB%L?`xh8QKmaoz@(T<K5x`7<`~m~Rpn^ak{S^l6 z3i=%%7{-gqU4E?x;}!UW7Z@M-4}1c=z~;c;-{r#uxL@%J!2XaI0_Md`@BCg*;CEht zYpj7SZ@<=q00H86c_CmJ<agaepn{k~BEQgpLIg2=*Do-j9>(2%g$eLuc8dK1gF?ZW zsij|F5FRl9pY<S^G30Ocpy1#6g8~Tukb{TkPrHIb1%8(U!ow@@JI_!k58ofM@xcDD zKPZ$JGjH}AfBcvf<rf$f%7;l}et|)F1O$F>U!dL}wg%w^W1`6~??Rz4{y+4>3&D)x zf2;Qo?aK=l_?<rpFYh0=1`z~9{%9jXzCYVn5R4f}{X!Qa$o~&*B=CowLZO1-e|Q)A z2Y-SBf7+zrKiDJ~{HG3pu<^TX0M>$;H~58TD46F@I{@7L&w6}<f3yb}_7C+0Aiu{Z zz;gfe1qk>L9Y7(FKjei%0OS3gX9%!0?gtF*Xli2zcf{V0uW91}$HZc84I~l`0u%rY z<GB?PmPim_IN0Anq9q~#m6d_Q1i(CkP(E2+9v&H4DZp!_1O#Oy1*N5-a$=zWTm_qw Y0dozGXlxGvv?;J>nweQvO^)FI0kr#l&j0`b literal 18853 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 H`u6_;($6RB diff --git a/lucene/docs/skin/images/apache-thanks.png b/lucene/docs/skin/images/apache-thanks.png new file mode 100644 index 0000000000000000000000000000000000000000..c0bea09cc8bcb9783fa3a67cb35db96f761002c3 GIT binary patch literal 4840 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 O0000<MNUMnLSTZI6a6ay literal 0 HcmV?d00001 diff --git a/lucene/docs/skin/images/built-with-cocoon.gif b/lucene/docs/skin/images/built-with-cocoon.gif new file mode 100644 index 0000000000000000000000000000000000000000..0b38f7857b6e621a964664dec8f6e12f07ff71de GIT binary patch literal 2252 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 Oy>%eWO^yh{r2ZePo82z} literal 0 HcmV?d00001 diff --git a/lucene/docs/systemrequirements.html b/lucene/docs/systemrequirements.html index e468f4c4e88..4025906ff9b 100644 --- a/lucene/docs/systemrequirements.html +++ b/lucene/docs/systemrequirements.html @@ -3,7 +3,7 @@ <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta content="Apache Forrest" name="Generator"> -<meta name="Forrest-version" content="0.8"> +<meta name="Forrest-version" content="0.9"> <meta name="Forrest-skin-name" content="lucene"> <title>Apache Lucene - System Requirements diff --git a/lucene/docs/systemrequirements.pdf b/lucene/docs/systemrequirements.pdf index f6b2924f0556ba8f827c5fe0afdd258e7a7ac729..1450224147807670d3944313d79130ce188f2d4e 100644 GIT binary patch literal 8301 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 diff --git a/lucene/src/java/org/apache/lucene/document/Document.java b/lucene/src/java/org/apache/lucene/document/Document.java index 0343f673e5a..5d8262c8940 100644 --- a/lucene/src/java/org/apache/lucene/document/Document.java +++ b/lucene/src/java/org/apache/lucene/document/Document.java @@ -131,8 +131,13 @@ public final class Document { /** Returns a field with the given name if any exist in this document, or * null. If multiple fields exists with this name, this method returns the * first value added. - * Do not use this method with lazy loaded fields. + * Do not use this method with lazy loaded fields or {@link NumericField}. + * @deprecated use {@link #getFieldable} instead and cast depending on + * data type. + * @throws ClassCastException if you try to retrieve a numerical or + * lazy loaded field. */ + @Deprecated public final Field getField(String name) { return (Field) getFieldable(name); } @@ -154,6 +159,8 @@ public final class Document { * this document, or null. If multiple fields exist with this name, this * method returns the first value added. If only binary fields with this name * exist, returns null. + * For {@link NumericField} it returns the string value of the number. If you want + * the actual {@code NumericField} instance back, use {@link #getFieldable}. */ public final String get(String name) { for (Fieldable field : fields) { @@ -177,13 +184,18 @@ public final class Document { /** * Returns an array of {@link Field}s with the given name. - * Do not use with lazy loaded fields. * This method returns an empty array when there are no * matching fields. It never returns null. + * Do not use this method with lazy loaded fields or {@link NumericField}. * * @param name the name of the field * @return a Field[] array + * @deprecated use {@link #getFieldable} instead and cast depending on + * data type. + * @throws ClassCastException if you try to retrieve a numerical or + * lazy loaded field. */ + @Deprecated public final Field[] getFields(String name) { List result = new ArrayList(); for (Fieldable field : fields) { @@ -230,6 +242,8 @@ public final class Document { * Returns an array of values of the field specified as the method parameter. * This method returns an empty array when there are no * matching fields. It never returns null. + * For {@link NumericField}s it returns the string value of the number. If you want + * the actual {@code NumericField} instances back, use {@link #getFieldables}. * @param name the name of the field * @return a String[] of field values */ diff --git a/lucene/src/java/org/apache/lucene/document/NumericField.java b/lucene/src/java/org/apache/lucene/document/NumericField.java index 6cae722a1d9..3bd46cf0e2f 100644 --- a/lucene/src/java/org/apache/lucene/document/NumericField.java +++ b/lucene/src/java/org/apache/lucene/document/NumericField.java @@ -127,18 +127,18 @@ import org.apache.lucene.search.FieldCache; // javadocs * class is a wrapper around this token stream type for * easier, more intuitive usage.

* - *

NOTE: This class is only used during - * indexing. When retrieving the stored field value from a - * {@link Document} instance after search, you will get a - * conventional {@link Fieldable} instance where the numeric - * values are returned as {@link String}s (according to - * toString(value) of the used data type). - * * @since 2.9 */ public final class NumericField extends AbstractField { - private final NumericTokenStream numericTS; + /** Data type of the value in {@link NumericField}. + * @since 3.2 + */ + public static enum DataType { INT, LONG, FLOAT, DOUBLE } + + private transient NumericTokenStream numericTS; + private DataType type; + private final int precisionStep; /** * Creates a field for numeric values using the default precisionStep @@ -158,8 +158,8 @@ public final class NumericField extends AbstractField { * a numeric value, before indexing a document containing this field, * set a value using the various set???Value() methods. * @param name the field name - * @param store if the field should be stored in plain text form - * (according to toString(value) of the used data type) + * @param store if the field should be stored, {@link Document#getFieldable} + * then returns {@code NumericField} instances on search results. * @param index if the field should be indexed using {@link NumericTokenStream} */ public NumericField(String name, Field.Store store, boolean index) { @@ -186,19 +186,43 @@ public final class NumericField extends AbstractField { * set a value using the various set???Value() methods. * @param name the field name * @param precisionStep the used precision step - * @param store if the field should be stored in plain text form - * (according to toString(value) of the used data type) + * @param store if the field should be stored, {@link Document#getFieldable} + * then returns {@code NumericField} instances on search results. * @param index if the field should be indexed using {@link NumericTokenStream} */ public NumericField(String name, int precisionStep, Field.Store store, boolean index) { super(name, store, index ? Field.Index.ANALYZED_NO_NORMS : Field.Index.NO, Field.TermVector.NO); + this.precisionStep = precisionStep; setOmitTermFreqAndPositions(true); - numericTS = new NumericTokenStream(precisionStep); } /** Returns a {@link NumericTokenStream} for indexing the numeric value. */ public TokenStream tokenStreamValue() { - return isIndexed() ? numericTS : null; + if (!isIndexed()) + return null; + if (numericTS == null) { + // lazy init the TokenStream as it is heavy to instantiate (attributes,...), + // if not needed (stored field loading) + numericTS = new NumericTokenStream(precisionStep); + // initialize value in TokenStream + if (fieldsData != null) { + assert type != null; + final Number val = (Number) fieldsData; + switch (type) { + case INT: + numericTS.setIntValue(val.intValue()); break; + case LONG: + numericTS.setLongValue(val.longValue()); break; + case FLOAT: + numericTS.setFloatValue(val.floatValue()); break; + case DOUBLE: + numericTS.setDoubleValue(val.doubleValue()); break; + default: + assert false : "Should never get here"; + } + } + } + return numericTS; } /** Returns always null for numeric fields */ @@ -212,7 +236,10 @@ public final class NumericField extends AbstractField { return null; } - /** Returns the numeric value as a string (how it is stored, when {@link Field.Store#YES} is chosen). */ + /** Returns the numeric value as a string. This format is also returned if you call {@link Document#get(String)} + * on search results. It is recommended to use {@link Document#getFieldable} instead + * that returns {@code NumericField} instances. You can then use {@link #getNumericValue} + * to return the stored value. */ public String stringValue() { return (fieldsData == null) ? null : fieldsData.toString(); } @@ -224,7 +251,14 @@ public final class NumericField extends AbstractField { /** Returns the precision step. */ public int getPrecisionStep() { - return numericTS.getPrecisionStep(); + return precisionStep; + } + + /** Returns the data type of the current value, {@code null} if not yet set. + * @since 3.2 + */ + public DataType getDataType() { + return type; } /** @@ -234,8 +268,9 @@ public final class NumericField extends AbstractField { * document.add(new NumericField(name, precisionStep).setLongValue(value)) */ public NumericField setLongValue(final long value) { - numericTS.setLongValue(value); + if (numericTS != null) numericTS.setLongValue(value); fieldsData = Long.valueOf(value); + type = DataType.LONG; return this; } @@ -246,8 +281,9 @@ public final class NumericField extends AbstractField { * document.add(new NumericField(name, precisionStep).setIntValue(value)) */ public NumericField setIntValue(final int value) { - numericTS.setIntValue(value); + if (numericTS != null) numericTS.setIntValue(value); fieldsData = Integer.valueOf(value); + type = DataType.INT; return this; } @@ -258,8 +294,9 @@ public final class NumericField extends AbstractField { * document.add(new NumericField(name, precisionStep).setDoubleValue(value)) */ public NumericField setDoubleValue(final double value) { - numericTS.setDoubleValue(value); + if (numericTS != null) numericTS.setDoubleValue(value); fieldsData = Double.valueOf(value); + type = DataType.DOUBLE; return this; } @@ -270,8 +307,9 @@ public final class NumericField extends AbstractField { * document.add(new NumericField(name, precisionStep).setFloatValue(value)) */ public NumericField setFloatValue(final float value) { - numericTS.setFloatValue(value); + if (numericTS != null) numericTS.setFloatValue(value); fieldsData = Float.valueOf(value); + type = DataType.FLOAT; return this; } diff --git a/lucene/src/java/org/apache/lucene/index/FieldsReader.java b/lucene/src/java/org/apache/lucene/index/FieldsReader.java index 76c0ed23552..e135d6d2870 100644 --- a/lucene/src/java/org/apache/lucene/index/FieldsReader.java +++ b/lucene/src/java/org/apache/lucene/index/FieldsReader.java @@ -24,10 +24,11 @@ import org.apache.lucene.document.Field; import org.apache.lucene.document.FieldSelector; import org.apache.lucene.document.FieldSelectorResult; import org.apache.lucene.document.Fieldable; -import org.apache.lucene.store.Directory; -import org.apache.lucene.store.IndexInput; +import org.apache.lucene.document.NumericField; import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.BufferedIndexInput; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.IndexInput; import org.apache.lucene.util.CloseableThreadLocal; import java.io.IOException; @@ -212,40 +213,39 @@ public final class FieldsReader implements Cloneable { Document doc = new Document(); int numFields = fieldsStream.readVInt(); - for (int i = 0; i < numFields; i++) { + out: for (int i = 0; i < numFields; i++) { int fieldNumber = fieldsStream.readVInt(); FieldInfo fi = fieldInfos.fieldInfo(fieldNumber); FieldSelectorResult acceptField = fieldSelector == null ? FieldSelectorResult.LOAD : fieldSelector.accept(fi.name); - byte bits = fieldsStream.readByte(); - assert bits <= FieldsWriter.FIELD_IS_TOKENIZED + FieldsWriter.FIELD_IS_BINARY; + int bits = fieldsStream.readByte() & 0xFF; + assert bits <= (FieldsWriter.FIELD_IS_NUMERIC_MASK | FieldsWriter.FIELD_IS_TOKENIZED | FieldsWriter.FIELD_IS_BINARY): "bits=" + Integer.toHexString(bits); boolean tokenize = (bits & FieldsWriter.FIELD_IS_TOKENIZED) != 0; boolean binary = (bits & FieldsWriter.FIELD_IS_BINARY) != 0; - //TODO: Find an alternative approach here if this list continues to grow beyond the - //list of 5 or 6 currently here. See Lucene 762 for discussion - if (acceptField.equals(FieldSelectorResult.LOAD)) { - addField(doc, fi, binary, tokenize); - } - else if (acceptField.equals(FieldSelectorResult.LOAD_AND_BREAK)){ - addField(doc, fi, binary, tokenize); - break;//Get out of this loop - } - else if (acceptField.equals(FieldSelectorResult.LAZY_LOAD)) { - addFieldLazy(doc, fi, binary, tokenize, true); - } - else if (acceptField.equals(FieldSelectorResult.LATENT)) { - addFieldLazy(doc, fi, binary, tokenize, false); - } - else if (acceptField.equals(FieldSelectorResult.SIZE)){ - skipField(addFieldSize(doc, fi, binary)); - } - else if (acceptField.equals(FieldSelectorResult.SIZE_AND_BREAK)){ - addFieldSize(doc, fi, binary); - break; - } - else { - skipField(); + final int numeric = bits & FieldsWriter.FIELD_IS_NUMERIC_MASK; + + switch (acceptField) { + case LOAD: + addField(doc, fi, binary, tokenize, numeric); + break; + case LOAD_AND_BREAK: + addField(doc, fi, binary, tokenize, numeric); + break out; //Get out of this loop + case LAZY_LOAD: + addFieldLazy(doc, fi, binary, tokenize, true, numeric); + break; + case LATENT: + addFieldLazy(doc, fi, binary, tokenize, false, numeric); + break; + case SIZE: + skipFieldBytes(addFieldSize(doc, fi, binary, numeric)); + break; + case SIZE_AND_BREAK: + addFieldSize(doc, fi, binary, numeric); + break out; //Get out of this loop + default: + skipField(numeric); } } @@ -282,72 +282,121 @@ public final class FieldsReader implements Cloneable { * Skip the field. We still have to read some of the information about the field, but can skip past the actual content. * This will have the most payoff on large fields. */ - private void skipField() throws IOException { - skipField(fieldsStream.readVInt()); + private void skipField(int numeric) throws IOException { + final int numBytes; + switch(numeric) { + case 0: + numBytes = fieldsStream.readVInt(); + break; + case FieldsWriter.FIELD_IS_NUMERIC_INT: + case FieldsWriter.FIELD_IS_NUMERIC_FLOAT: + numBytes = 4; + break; + case FieldsWriter.FIELD_IS_NUMERIC_LONG: + case FieldsWriter.FIELD_IS_NUMERIC_DOUBLE: + numBytes = 8; + break; + default: + throw new FieldReaderException("Invalid numeric type: " + Integer.toHexString(numeric)); + } + + skipFieldBytes(numBytes); } - private void skipField(int toRead) throws IOException { + private void skipFieldBytes(int toRead) throws IOException { fieldsStream.seek(fieldsStream.getFilePointer() + toRead); } - private void addFieldLazy(Document doc, FieldInfo fi, boolean binary, boolean tokenize, boolean cacheResult) throws IOException { + private NumericField loadNumericField(FieldInfo fi, int numeric) throws IOException { + assert numeric != 0; + switch(numeric) { + case FieldsWriter.FIELD_IS_NUMERIC_INT: + return new NumericField(fi.name, Field.Store.YES, fi.isIndexed).setIntValue(fieldsStream.readInt()); + case FieldsWriter.FIELD_IS_NUMERIC_LONG: + return new NumericField(fi.name, Field.Store.YES, fi.isIndexed).setLongValue(fieldsStream.readLong()); + case FieldsWriter.FIELD_IS_NUMERIC_FLOAT: + return new NumericField(fi.name, Field.Store.YES, fi.isIndexed).setFloatValue(Float.intBitsToFloat(fieldsStream.readInt())); + case FieldsWriter.FIELD_IS_NUMERIC_DOUBLE: + return new NumericField(fi.name, Field.Store.YES, fi.isIndexed).setDoubleValue(Double.longBitsToDouble(fieldsStream.readLong())); + default: + throw new FieldReaderException("Invalid numeric type: " + Integer.toHexString(numeric)); + } + } + + private void addFieldLazy(Document doc, FieldInfo fi, boolean binary, boolean tokenize, boolean cacheResult, int numeric) throws IOException { + final AbstractField f; if (binary) { int toRead = fieldsStream.readVInt(); long pointer = fieldsStream.getFilePointer(); - //was: doc.add(new Fieldable(fi.name, b, Fieldable.Store.YES)); - doc.add(new LazyField(fi.name, Field.Store.YES, toRead, pointer, binary, cacheResult)); + f = new LazyField(fi.name, Field.Store.YES, toRead, pointer, binary, cacheResult); //Need to move the pointer ahead by toRead positions fieldsStream.seek(pointer + toRead); + } else if (numeric != 0) { + f = loadNumericField(fi, numeric); } else { Field.Store store = Field.Store.YES; Field.Index index = Field.Index.toIndex(fi.isIndexed, tokenize); Field.TermVector termVector = Field.TermVector.toTermVector(fi.storeTermVector, fi.storeOffsetWithTermVector, fi.storePositionWithTermVector); - AbstractField f; int length = fieldsStream.readVInt(); long pointer = fieldsStream.getFilePointer(); //Skip ahead of where we are by the length of what is stored fieldsStream.seek(pointer+length); f = new LazyField(fi.name, store, index, termVector, length, pointer, binary, cacheResult); - f.setOmitNorms(fi.omitNorms); - f.setOmitTermFreqAndPositions(fi.omitTermFreqAndPositions); - - doc.add(f); } - + + f.setOmitNorms(fi.omitNorms); + f.setOmitTermFreqAndPositions(fi.omitTermFreqAndPositions); + doc.add(f); } - private void addField(Document doc, FieldInfo fi, boolean binary, boolean tokenize) throws CorruptIndexException, IOException { + private void addField(Document doc, FieldInfo fi, boolean binary, boolean tokenize, int numeric) throws CorruptIndexException, IOException { + final AbstractField f; if (binary) { int toRead = fieldsStream.readVInt(); final byte[] b = new byte[toRead]; fieldsStream.readBytes(b, 0, b.length); - doc.add(new Field(fi.name, b)); + f = new Field(fi.name, b); + } else if (numeric != 0) { + f = loadNumericField(fi, numeric); } else { - Field.Store store = Field.Store.YES; Field.Index index = Field.Index.toIndex(fi.isIndexed, tokenize); Field.TermVector termVector = Field.TermVector.toTermVector(fi.storeTermVector, fi.storeOffsetWithTermVector, fi.storePositionWithTermVector); - - AbstractField f; f = new Field(fi.name, // name - false, - fieldsStream.readString(), // read value - store, - index, - termVector); - f.setOmitTermFreqAndPositions(fi.omitTermFreqAndPositions); - f.setOmitNorms(fi.omitNorms); - - doc.add(f); + false, + fieldsStream.readString(), // read value + Field.Store.YES, + index, + termVector); } + + f.setOmitTermFreqAndPositions(fi.omitTermFreqAndPositions); + f.setOmitNorms(fi.omitNorms); + doc.add(f); } // Add the size of field as a byte[] containing the 4 bytes of the integer byte size (high order byte first; char = 2 bytes) // Read just the size -- caller must skip the field content to continue reading fields // Return the size in bytes or chars, depending on field type - private int addFieldSize(Document doc, FieldInfo fi, boolean binary) throws IOException { - int size = fieldsStream.readVInt(), bytesize = binary ? size : 2*size; + private int addFieldSize(Document doc, FieldInfo fi, boolean binary, int numeric) throws IOException { + final int bytesize, size; + switch(numeric) { + case 0: + size = fieldsStream.readVInt(); + bytesize = binary ? size : 2*size; + break; + case FieldsWriter.FIELD_IS_NUMERIC_INT: + case FieldsWriter.FIELD_IS_NUMERIC_FLOAT: + size = bytesize = 4; + break; + case FieldsWriter.FIELD_IS_NUMERIC_LONG: + case FieldsWriter.FIELD_IS_NUMERIC_DOUBLE: + size = bytesize = 8; + break; + default: + throw new FieldReaderException("Invalid numeric type: " + Integer.toHexString(numeric)); + } byte[] sizebytes = new byte[4]; sizebytes[0] = (byte) (bytesize>>>24); sizebytes[1] = (byte) (bytesize>>>16); @@ -358,7 +407,7 @@ public final class FieldsReader implements Cloneable { } /** - * A Lazy implementation of Fieldable that differs loading of fields until asked for, instead of when the Document is + * A Lazy implementation of Fieldable that defers loading of fields until asked for, instead of when the Document is * loaded. */ private class LazyField extends AbstractField implements Fieldable { diff --git a/lucene/src/java/org/apache/lucene/index/FieldsWriter.java b/lucene/src/java/org/apache/lucene/index/FieldsWriter.java index 303aa912bc3..9efd909574e 100644 --- a/lucene/src/java/org/apache/lucene/index/FieldsWriter.java +++ b/lucene/src/java/org/apache/lucene/index/FieldsWriter.java @@ -21,22 +21,40 @@ import java.util.List; import org.apache.lucene.document.Document; import org.apache.lucene.document.Fieldable; +import org.apache.lucene.document.NumericField; import org.apache.lucene.store.Directory; import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexOutput; import org.apache.lucene.util.IOUtils; final class FieldsWriter { - static final byte FIELD_IS_TOKENIZED = 0x1; - static final byte FIELD_IS_BINARY = 0x2; + static final int FIELD_IS_TOKENIZED = 1 << 0; + static final int FIELD_IS_BINARY = 1 << 1; + // the old bit 1 << 2 was compressed, is now left out + + private static final int _NUMERIC_BIT_SHIFT = 3; + static final int FIELD_IS_NUMERIC_MASK = 0x07 << _NUMERIC_BIT_SHIFT; + + static final int FIELD_IS_NUMERIC_INT = 1 << _NUMERIC_BIT_SHIFT; + static final int FIELD_IS_NUMERIC_LONG = 2 << _NUMERIC_BIT_SHIFT; + static final int FIELD_IS_NUMERIC_FLOAT = 3 << _NUMERIC_BIT_SHIFT; + static final int FIELD_IS_NUMERIC_DOUBLE = 4 << _NUMERIC_BIT_SHIFT; + // currently unused: static final int FIELD_IS_NUMERIC_SHORT = 5 << _NUMERIC_BIT_SHIFT; + // currently unused: static final int FIELD_IS_NUMERIC_BYTE = 6 << _NUMERIC_BIT_SHIFT; + + // the next possible bits are: 1 << 6; 1 << 7 + // Lucene 3.0: Removal of compressed fields static final int FORMAT_LUCENE_3_0_NO_COMPRESSED_FIELDS = 2; + // Lucene 3.2: NumericFields are stored in binary format + static final int FORMAT_LUCENE_3_2_NUMERIC_FIELDS = 3; + // NOTE: if you introduce a new format, make it 1 higher // than the current one, and always change this if you // switch to a new format! - static final int FORMAT_CURRENT = FORMAT_LUCENE_3_0_NO_COMPRESSED_FIELDS; + static final int FORMAT_CURRENT = FORMAT_LUCENE_3_2_NUMERIC_FIELDS; // when removing support for old versions, leave the last supported version here static final int FORMAT_MINIMUM = FORMAT_LUCENE_3_0_NO_COMPRESSED_FIELDS; @@ -121,13 +139,26 @@ final class FieldsWriter { final void writeField(int fieldNumber, Fieldable field) throws IOException { fieldsStream.writeVInt(fieldNumber); - byte bits = 0; + int bits = 0; if (field.isTokenized()) - bits |= FieldsWriter.FIELD_IS_TOKENIZED; + bits |= FIELD_IS_TOKENIZED; if (field.isBinary()) - bits |= FieldsWriter.FIELD_IS_BINARY; - - fieldsStream.writeByte(bits); + bits |= FIELD_IS_BINARY; + if (field instanceof NumericField) { + switch (((NumericField) field).getDataType()) { + case INT: + bits |= FIELD_IS_NUMERIC_INT; break; + case LONG: + bits |= FIELD_IS_NUMERIC_LONG; break; + case FLOAT: + bits |= FIELD_IS_NUMERIC_FLOAT; break; + case DOUBLE: + bits |= FIELD_IS_NUMERIC_DOUBLE; break; + default: + assert false : "Should never get here"; + } + } + fieldsStream.writeByte((byte) bits); if (field.isBinary()) { final byte[] data; @@ -139,8 +170,22 @@ final class FieldsWriter { fieldsStream.writeVInt(len); fieldsStream.writeBytes(data, offset, len); - } - else { + } else if (field instanceof NumericField) { + final NumericField nf = (NumericField) field; + final Number n = nf.getNumericValue(); + switch (nf.getDataType()) { + case INT: + fieldsStream.writeInt(n.intValue()); break; + case LONG: + fieldsStream.writeLong(n.longValue()); break; + case FLOAT: + fieldsStream.writeInt(Float.floatToIntBits(n.floatValue())); break; + case DOUBLE: + fieldsStream.writeLong(Double.doubleToLongBits(n.doubleValue())); break; + default: + assert false : "Should never get here"; + } + } else { fieldsStream.writeString(field.stringValue()); } } diff --git a/lucene/src/site/src/documentation/content/xdocs/fileformats.xml b/lucene/src/site/src/documentation/content/xdocs/fileformats.xml index 17ca5346a9f..228e18a2b62 100644 --- a/lucene/src/site/src/documentation/content/xdocs/fileformats.xml +++ b/lucene/src/site/src/documentation/content/xdocs/fileformats.xml @@ -94,6 +94,11 @@ Additionally segments track explicitly whether or not they have term vectors. See LUCENE-2811 for details.

+

+ In version 3.2, numeric fields are written as natively + to stored fields file, previously they were stored in + text format only. +

Definitions @@ -1300,10 +1305,18 @@
  • third bit is one for fields with compression option enabled (if compression is enabled, the algorithm used is ZLIB), only available for indexes until Lucene version 2.9.x
  • +
  • 4th to 6th bits (mask: 0x7<<3) define the type of a + numeric field:
      +
    • all bits in mask are cleared if no numeric field at all
    • +
    • 1<<3: Value is Int
    • +
    • 2<<3: Value is Long
    • +
    • 3<<3: Value is Int as Float (as of Integer.intBitsToFloat)
    • +
    • 4<<3: Value is Long as Double (as of Double.longBitsToDouble)
    • +
  • Value --> - String | BinaryValue (depending on Bits) + String | BinaryValue | Int | Long (depending on Bits)

    BinaryValue --> ValueSize, <Byte>^ValueSize diff --git a/lucene/src/site/src/documentation/content/xdocs/gettingstarted.xml b/lucene/src/site/src/documentation/content/xdocs/gettingstarted.xml index 4dde0f34ecb..7ab6441214e 100644 --- a/lucene/src/site/src/documentation/content/xdocs/gettingstarted.xml +++ b/lucene/src/site/src/documentation/content/xdocs/gettingstarted.xml @@ -28,11 +28,11 @@ may wish to skip sections.

    diff --git a/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java b/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java index e467499f4a2..72c702acfa6 100644 --- a/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java +++ b/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java @@ -90,6 +90,8 @@ public class TestBackwardsCompatibility extends LuceneTestCase { "30.nocfs", "31.cfs", "31.nocfs", + "32.cfs", + "32.nocfs", }; final String[] unsupportedNames = {"19.cfs", diff --git a/lucene/src/test/org/apache/lucene/index/TestFieldsReader.java b/lucene/src/test/org/apache/lucene/index/TestFieldsReader.java index 26b1717072f..75a9be9cc0e 100644 --- a/lucene/src/test/org/apache/lucene/index/TestFieldsReader.java +++ b/lucene/src/test/org/apache/lucene/index/TestFieldsReader.java @@ -24,12 +24,14 @@ import java.util.*; import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; +import org.apache.lucene.document.NumericField; import org.apache.lucene.document.FieldSelector; import org.apache.lucene.document.FieldSelectorResult; import org.apache.lucene.document.Fieldable; import org.apache.lucene.document.LoadFirstFieldSelector; import org.apache.lucene.document.SetBasedFieldSelector; import org.apache.lucene.index.IndexWriterConfig.OpenMode; +import org.apache.lucene.search.FieldCache; import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.BufferedIndexInput; import org.apache.lucene.store.Directory; @@ -511,4 +513,69 @@ public class TestFieldsReader extends LuceneTestCase { } } + + public void testNumericField() throws Exception { + Directory dir = newDirectory(); + RandomIndexWriter w = new RandomIndexWriter(random, dir); + final int numDocs = _TestUtil.nextInt(random, 500, 1000) * RANDOM_MULTIPLIER; + final Number[] answers = new Number[numDocs]; + final NumericField.DataType[] typeAnswers = new NumericField.DataType[numDocs]; + for(int id=0;id=64) precisionStep=Integer.MAX_VALUE; - - CharFilterFactory[] filterFactories = new CharFilterFactory[0]; - TokenFilterFactory[] tokenFilterFactories = new TokenFilterFactory[0]; - analyzer = new TokenizerChain(filterFactories, new TrieTokenizerFactory(TrieField.TrieTypes.DATE, precisionStep), tokenFilterFactories); - // for query time we only need one token, so we use the biggest possible precisionStep: - queryAnalyzer = new TokenizerChain(filterFactories, new TrieTokenizerFactory(TrieField.TrieTypes.DATE, Integer.MAX_VALUE), tokenFilterFactories); + wrappedField.init(schema, args); + analyzer = wrappedField.analyzer; + queryAnalyzer = wrappedField.queryAnalyzer; } @Override public Date toObject(Fieldable f) { - byte[] arr = f.getBinaryValue(); - if (arr==null) throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,TrieField.badFieldString(f)); - return new Date(TrieFieldHelper.toLong(arr)); + return (Date) wrappedField.toObject(f); } @Override public Object toObject(SchemaField sf, BytesRef term) { - return new Date(NumericUtils.prefixCodedToLong(term)); + return wrappedField.toObject(sf, term); } @Override public SortField getSortField(SchemaField field, boolean top) { - field.checkSortability(); - - int flags = CachedArrayCreator.CACHE_VALUES_AND_BITS; - boolean sortMissingLast = field.sortMissingLast(); - boolean sortMissingFirst = field.sortMissingFirst(); - - Object missingValue = null; - if( sortMissingLast ) { - missingValue = top ? Long.MIN_VALUE : Long.MAX_VALUE; - } else if( sortMissingFirst ) { - missingValue = top ? Long.MAX_VALUE : Long.MIN_VALUE; - } - return new SortField(new LongValuesCreator(field.getName(), FieldCache.NUMERIC_UTILS_LONG_PARSER, flags), top).setMissingValue(missingValue); + return wrappedField.getSortField(field, top); } @Override public ValueSource getValueSource(SchemaField field, QParser parser) { - field.checkFieldCacheSource(parser); - return new TrieDateFieldSource( new LongValuesCreator( field.getName(), FieldCache.NUMERIC_UTILS_LONG_PARSER, CachedArrayCreator.CACHE_VALUES_AND_BITS )); - } - - @Override - public void write(TextResponseWriter writer, String name, Fieldable f) throws IOException { - byte[] arr = f.getBinaryValue(); - if (arr==null) { - writer.writeStr(name, TrieField.badFieldString(f),true); - return; - } - - writer.writeDate(name,new Date(TrieFieldHelper.toLong(arr))); - } - - @Override - public boolean isTokenized() { - return true; + return wrappedField.getValueSource(field, parser); } /** * @return the precisionStep used to index values into the field */ public int getPrecisionStep() { - return precisionStepArg; + return wrappedField.getPrecisionStep(); } + @Override + public void write(TextResponseWriter writer, String name, Fieldable f) throws IOException { + wrappedField.write(writer, name, f); + } + + @Override + public boolean isTokenized() { + return wrappedField.isTokenized(); + } + + @Override + public boolean multiValuedFieldCache() { + return wrappedField.multiValuedFieldCache(); + } @Override public String storedToReadable(Fieldable f) { - return toExternal(f); + return wrappedField.storedToReadable(f); } @Override public String readableToIndexed(String val) { - // TODO: Numeric should never be handled as String, that may break in future lucene versions! Change to use BytesRef for term texts! - BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_LONG); - NumericUtils.longToPrefixCoded(super.parseMath(null, val).getTime(), 0, bytes); - return bytes.utf8ToString(); + return wrappedField.readableToIndexed(val); } @Override public String toInternal(String val) { - return readableToIndexed(val); + return wrappedField.toInternal(val); } @Override public String toExternal(Fieldable f) { - byte[] arr = f.getBinaryValue(); - if (arr==null) return TrieField.badFieldString(f); - return super.toExternal(new Date(TrieFieldHelper.toLong(arr))); + return wrappedField.toExternal(f); } @Override public String indexedToReadable(String _indexedForm) { - final BytesRef indexedForm = new BytesRef(_indexedForm); - return super.toExternal( new Date(NumericUtils.prefixCodedToLong(indexedForm)) ); + return wrappedField.indexedToReadable(_indexedForm); } @Override public void indexedToReadable(BytesRef input, CharArr out) { - String ext = super.toExternal( new Date(NumericUtils.prefixCodedToLong(input)) ); - out.write(ext); + wrappedField.indexedToReadable(input, out); } @Override public String storedToIndexed(Fieldable f) { - // TODO: optimize to remove redundant string conversion - return readableToIndexed(storedToReadable(f)); + return wrappedField.storedToIndexed(f); } @Override public Fieldable createField(SchemaField field, Object value, float boost) { - boolean indexed = field.indexed(); - boolean stored = field.stored(); - - if (!indexed && !stored) { - if (log.isTraceEnabled()) - log.trace("Ignoring unindexed/unstored field: " + field); - return null; - } - - int ps = precisionStep; - - byte[] arr=null; - TokenStream ts=null; - - long time = (value instanceof Date) - ? ((Date)value).getTime() - : super.parseMath(null, value.toString()).getTime(); - - if (stored) arr = TrieFieldHelper.toArr(time); - if (indexed) ts = new NumericTokenStream(ps).setLongValue(time); - - Field f; - if (stored) { - f = new Field(field.getName(), arr); - if (indexed) f.setTokenStream(ts); - } else { - f = new Field(field.getName(), ts); - } - - // term vectors aren't supported - - f.setOmitNorms(field.omitNorms()); - f.setOmitTermFreqAndPositions(field.omitTf()); - f.setBoost(boost); - return f; + return wrappedField.createField(field, value, boost); } @Override public Query getRangeQuery(QParser parser, SchemaField field, String min, String max, boolean minInclusive, boolean maxInclusive) { - return getRangeQuery(parser, field, - min==null ? null : super.parseMath(null,min), - max==null ? null : super.parseMath(null,max), - minInclusive, maxInclusive); + return wrappedField.getRangeQuery(parser, field, min, max, minInclusive, maxInclusive); } @Override public Query getRangeQuery(QParser parser, SchemaField sf, Date min, Date max, boolean minInclusive, boolean maxInclusive) { - int ps = precisionStep; - Query query = NumericRangeQuery.newLongRange(sf.getName(), ps, + return NumericRangeQuery.newLongRange(sf.getName(), wrappedField.precisionStep, min == null ? null : min.getTime(), max == null ? null : max.getTime(), minInclusive, maxInclusive); - - return query; } } diff --git a/solr/src/java/org/apache/solr/schema/TrieField.java b/solr/src/java/org/apache/solr/schema/TrieField.java index e670ba0e338..eb78e1bbfd8 100644 --- a/solr/src/java/org/apache/solr/schema/TrieField.java +++ b/solr/src/java/org/apache/solr/schema/TrieField.java @@ -17,6 +17,8 @@ package org.apache.solr.schema; import org.apache.lucene.document.Fieldable; +import org.apache.lucene.document.Field; +import org.apache.lucene.document.NumericField; import org.apache.lucene.search.*; import org.apache.lucene.search.cache.CachedArrayCreator; import org.apache.lucene.search.cache.DoubleValuesCreator; @@ -40,17 +42,17 @@ import java.util.Map; import java.util.Date; /** - * Provides field types to support for Lucene's Trie Range Queries. + * Provides field types to support for Lucene's {@link NumericField}. * See {@link org.apache.lucene.search.NumericRangeQuery} for more details. * It supports integer, float, long, double and date types. *

    * For each number being added to this field, multiple terms are generated as per the algorithm described in the above - * link. The possible number of terms increases dramatically with higher precision steps (factor 2^precisionStep). For + * link. The possible number of terms increases dramatically with lower precision steps. For * the fast range search to work, trie fields must be indexed. *

    * Trie fields are sortable in numerical order and can be used in function queries. *

    - * Note that if you use a precisionStep of 32 for int/float and 64 for long/double, then multiple terms will not be + * Note that if you use a precisionStep of 32 for int/float and 64 for long/double/date, then multiple terms will not be * generated, range search will be no faster than any other number field, but sorting will still be possible. * * @version $Id$ @@ -101,21 +103,28 @@ public class TrieField extends FieldType { @Override public Object toObject(Fieldable f) { - byte[] arr = f.getBinaryValue(); - if (arr==null) return badFieldString(f); - switch (type) { - case INTEGER: - return TrieFieldHelper.toInt(arr); - case FLOAT: - return TrieFieldHelper.toFloat(arr); - case LONG: - return TrieFieldHelper.toLong(arr); - case DOUBLE: - return TrieFieldHelper.toDouble(arr); - case DATE: - return new Date(TrieFieldHelper.toLong(arr)); - default: - throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + f.name()); + if (f instanceof NumericField) { + final Number val = ((NumericField) f).getNumericValue(); + if (val==null) return badFieldString(f); + return (type == TrieTypes.DATE) ? new Date(val.longValue()) : val; + } else { + // the following code is "deprecated" and only to support pre-3.2 indexes using the old BinaryField encoding: + final byte[] arr = f.getBinaryValue(); + if (arr==null) return badFieldString(f); + switch (type) { + case INTEGER: + return toInt(arr); + case FLOAT: + return Float.intBitsToFloat(toInt(arr)); + case LONG: + return toLong(arr); + case DOUBLE: + return Double.longBitsToDouble(toLong(arr)); + case DATE: + return new Date(toLong(arr)); + default: + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + f.name()); + } } } @@ -198,30 +207,7 @@ public class TrieField extends FieldType { @Override public void write(TextResponseWriter writer, String name, Fieldable f) throws IOException { - byte[] arr = f.getBinaryValue(); - if (arr==null) { - writer.writeStr(name, badFieldString(f),true); - return; - } - switch (type) { - case INTEGER: - writer.writeInt(name,TrieFieldHelper.toInt(arr)); - break; - case FLOAT: - writer.writeFloat(name,TrieFieldHelper.toFloat(arr)); - break; - case LONG: - writer.writeLong(name,TrieFieldHelper.toLong(arr)); - break; - case DOUBLE: - writer.writeDouble(name,TrieFieldHelper.toDouble(arr)); - break; - case DATE: - writer.writeDate(name,new Date(TrieFieldHelper.toLong(arr))); - break; - default: - throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + f.name()); - } + writer.writeVal(name, toObject(f)); } @Override @@ -290,6 +276,17 @@ public class TrieField extends FieldType { return query; } + @Deprecated + static int toInt(byte[] arr) { + return (arr[0]<<24) | ((arr[1]&0xff)<<16) | ((arr[2]&0xff)<<8) | (arr[3]&0xff); + } + + @Deprecated + static long toLong(byte[] arr) { + int high = (arr[0]<<24) | ((arr[1]&0xff)<<16) | ((arr[2]&0xff)<<8) | (arr[3]&0xff); + int low = (arr[4]<<24) | ((arr[5]&0xff)<<16) | ((arr[6]&0xff)<<8) | (arr[7]&0xff); + return (((long)high)<<32) | (low&0x0ffffffffL); + } @Override public String storedToReadable(Fieldable f) { @@ -341,22 +338,9 @@ public class TrieField extends FieldType { @Override public String toExternal(Fieldable f) { - byte[] arr = f.getBinaryValue(); - if (arr==null) return badFieldString(f); - switch (type) { - case INTEGER: - return Integer.toString(TrieFieldHelper.toInt(arr)); - case FLOAT: - return Float.toString(TrieFieldHelper.toFloat(arr)); - case LONG: - return Long.toString(TrieFieldHelper.toLong(arr)); - case DOUBLE: - return Double.toString(TrieFieldHelper.toDouble(arr)); - case DATE: - return dateField.formatDate(new Date(TrieFieldHelper.toLong(arr))); - default: - throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + f.name()); - } + return (type == TrieTypes.DATE) + ? dateField.toExternal((Date) toObject(f)) + : toObject(f).toString(); } @Override @@ -372,7 +356,7 @@ public class TrieField extends FieldType { case DOUBLE: return Double.toString( NumericUtils.sortableLongToDouble(NumericUtils.prefixCodedToLong(indexedForm)) ); case DATE: - return dateField.formatDate( new Date(NumericUtils.prefixCodedToLong(indexedForm)) ); + return dateField.toExternal( new Date(NumericUtils.prefixCodedToLong(indexedForm)) ); default: throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + type); } @@ -397,7 +381,7 @@ public class TrieField extends FieldType { s = Double.toString( NumericUtils.sortableLongToDouble(NumericUtils.prefixCodedToLong(indexedForm)) ); break; case DATE: - s = dateField.formatDate( new Date(NumericUtils.prefixCodedToLong(indexedForm)) ); + s = dateField.toExternal( new Date(NumericUtils.prefixCodedToLong(indexedForm)) ); break; default: throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + type); @@ -426,59 +410,117 @@ public class TrieField extends FieldType { @Override public String storedToIndexed(Fieldable f) { - // TODO: optimize to remove redundant string conversion - return readableToIndexed(storedToReadable(f)); + final BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_LONG); + if (f instanceof NumericField) { + final Number val = ((NumericField) f).getNumericValue(); + if (val==null) + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Invalid field contents: "+f.name()); + switch (type) { + case INTEGER: + NumericUtils.intToPrefixCoded(val.intValue(), 0, bytes); + break; + case FLOAT: + NumericUtils.intToPrefixCoded(NumericUtils.floatToSortableInt(val.floatValue()), 0, bytes); + break; + case LONG: //fallthrough! + case DATE: + NumericUtils.longToPrefixCoded(val.longValue(), 0, bytes); + break; + case DOUBLE: + NumericUtils.longToPrefixCoded(NumericUtils.doubleToSortableLong(val.doubleValue()), 0, bytes); + break; + default: + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + f.name()); + } + } else { + // the following code is "deprecated" and only to support pre-3.2 indexes using the old BinaryField encoding: + final byte[] arr = f.getBinaryValue(); + if (arr==null) + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Invalid field contents: "+f.name()); + switch (type) { + case INTEGER: + NumericUtils.intToPrefixCoded(toInt(arr), 0, bytes); + break; + case FLOAT: { + // WARNING: Code Duplication! Keep in sync with o.a.l.util.NumericUtils! + // copied from NumericUtils to not convert to/from float two times + // code in next 2 lines is identical to: int v = NumericUtils.floatToSortableInt(Float.intBitsToFloat(toInt(arr))); + int v = toInt(arr); + if (v<0) v ^= 0x7fffffff; + NumericUtils.intToPrefixCoded(v, 0, bytes); + break; + } + case LONG: //fallthrough! + case DATE: + NumericUtils.longToPrefixCoded(toLong(arr), 0, bytes); + break; + case DOUBLE: { + // WARNING: Code Duplication! Keep in sync with o.a.l.util.NumericUtils! + // copied from NumericUtils to not convert to/from double two times + // code in next 2 lines is identical to: long v = NumericUtils.doubleToSortableLong(Double.longBitsToDouble(toLong(arr))); + long v = toLong(arr); + if (v<0) v ^= 0x7fffffffffffffffL; + NumericUtils.longToPrefixCoded(v, 0, bytes); + break; + } + default: + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + f.name()); + } + } + return bytes.utf8ToString(); } @Override public Fieldable createField(SchemaField field, Object value, float boost) { - TrieFieldHelper.FieldInfo info = new TrieFieldHelper.FieldInfo(); - info.index = field.indexed(); - info.store = field.stored(); - info.precisionStep = precisionStep; - info.omitNorms = field.omitNorms(); - info.omitTF = field.omitTf(); - - if (!info.index && !info.store) { + boolean indexed = field.indexed(); + boolean stored = field.stored(); + + if (!indexed && !stored) { if (log.isTraceEnabled()) log.trace("Ignoring unindexed/unstored field: " + field); return null; } + final NumericField f = new NumericField(field.getName(), precisionStep, stored ? Field.Store.YES : Field.Store.NO, indexed); switch (type) { case INTEGER: int i = (value instanceof Number) ? ((Number)value).intValue() : Integer.parseInt(value.toString()); - return TrieFieldHelper.createIntField(field.getName(), i, info, boost); - + f.setIntValue(i); + break; case FLOAT: - float f = (value instanceof Number) + float fl = (value instanceof Number) ? ((Number)value).floatValue() : Float.parseFloat(value.toString()); - return TrieFieldHelper.createFloatField(field.getName(), f, info, boost); - + f.setFloatValue(fl); + break; case LONG: long l = (value instanceof Number) ? ((Number)value).longValue() : Long.parseLong(value.toString()); - return TrieFieldHelper.createLongField(field.getName(), l, info, boost); - + f.setLongValue(l); + break; case DOUBLE: double d = (value instanceof Number) ? ((Number)value).doubleValue() : Double.parseDouble(value.toString()); - return TrieFieldHelper.createDoubleField(field.getName(), d, info, boost); - + f.setDoubleValue(d); + break; case DATE: Date date = (value instanceof Date) ? ((Date)value) : dateField.parseMath(null, value.toString()); - return TrieFieldHelper.createDateField(field.getName(), date, info, boost); - + f.setLongValue(date.getTime()); + break; default: throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + type); } + + f.setOmitNorms(field.omitNorms()); + f.setOmitTermFreqAndPositions(field.omitTf()); + f.setBoost(boost); + return f; } public enum TrieTypes { @@ -498,14 +540,12 @@ public class TrieField extends FieldType { * that indexes multiple precisions per value. */ public static String getMainValuePrefix(FieldType ft) { - if (ft instanceof TrieDateField) { - int step = ((TrieDateField)ft).getPrecisionStep(); - if (step <= 0 || step >=64) return null; - return LONG_PREFIX; - } else if (ft instanceof TrieField) { - TrieField trie = (TrieField)ft; - if (trie.precisionStep == Integer.MAX_VALUE) return null; - + if (ft instanceof TrieDateField) + ft = ((TrieDateField) ft).wrappedField; + if (ft instanceof TrieField) { + final TrieField trie = (TrieField)ft; + if (trie.precisionStep == Integer.MAX_VALUE) + return null; switch (trie.type) { case INTEGER: case FLOAT: diff --git a/solr/src/java/org/apache/solr/schema/TrieFieldHelper.java b/solr/src/java/org/apache/solr/schema/TrieFieldHelper.java deleted file mode 100644 index c40ecd87a78..00000000000 --- a/solr/src/java/org/apache/solr/schema/TrieFieldHelper.java +++ /dev/null @@ -1,166 +0,0 @@ -/** - * Copyright 2005 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.Date; - -import org.apache.lucene.analysis.NumericTokenStream; -import org.apache.lucene.analysis.TokenStream; -import org.apache.lucene.document.Field; -import org.apache.lucene.document.Fieldable; - -/** - * Helper class to make TrieFields compatible with ones written in solr - * - * TODO -- Something like this should be in in lucene - * see: LUCENE-3001 - */ -public class TrieFieldHelper { - - private TrieFieldHelper() {} - - public static class FieldInfo { - public int precisionStep = 8; // same as solr default - public boolean store = true; - public boolean index = true; - public boolean omitNorms = true; - public boolean omitTF = true; - } - - //---------------------------------------------- - // Create Field - //---------------------------------------------- - - private static Fieldable createField(String name, byte[] arr, TokenStream ts, FieldInfo info, float boost) { - - Field f; - if (info.store) { - f = new Field(name, arr); - if (info.index) f.setTokenStream(ts); - } else { - f = new Field(name, ts); - } - - // term vectors aren't supported - f.setOmitNorms(info.omitNorms); - f.setOmitTermFreqAndPositions(info.omitTF); - f.setBoost(boost); - return f; - } - - public static Fieldable createIntField(String name, int value, FieldInfo info, float boost) { - - byte[] arr=null; - TokenStream ts=null; - - if (info.store) arr = TrieFieldHelper.toArr(value); - if (info.index) ts = new NumericTokenStream(info.precisionStep).setIntValue(value); - - return createField(name, arr, ts, info, boost); - } - - public static Fieldable createFloatField(String name, float value, FieldInfo info, float boost) { - - byte[] arr=null; - TokenStream ts=null; - - if (info.store) arr = TrieFieldHelper.toArr(value); - if (info.index) ts = new NumericTokenStream(info.precisionStep).setFloatValue(value); - - return createField(name, arr, ts, info, boost); - } - - public static Fieldable createLongField(String name, long value, FieldInfo info, float boost) { - - byte[] arr=null; - TokenStream ts=null; - - if (info.store) arr = TrieFieldHelper.toArr(value); - if (info.index) ts = new NumericTokenStream(info.precisionStep).setLongValue(value); - - return createField(name, arr, ts, info, boost); - } - - public static Fieldable createDoubleField(String name, double value, FieldInfo info, float boost) { - - byte[] arr=null; - TokenStream ts=null; - - if (info.store) arr = TrieFieldHelper.toArr(value); - if (info.index) ts = new NumericTokenStream(info.precisionStep).setDoubleValue(value); - - return createField(name, arr, ts, info, boost); - } - - public static Fieldable createDateField(String name, Date value, FieldInfo info, float boost) { - // TODO, make sure the date is within long range! - return createLongField(name, value.getTime(), info, boost); - } - - - //---------------------------------------------- - // number <=> byte[] - //---------------------------------------------- - - public static int toInt(byte[] arr) { - return (arr[0]<<24) | ((arr[1]&0xff)<<16) | ((arr[2]&0xff)<<8) | (arr[3]&0xff); - } - - public static long toLong(byte[] arr) { - int high = (arr[0]<<24) | ((arr[1]&0xff)<<16) | ((arr[2]&0xff)<<8) | (arr[3]&0xff); - int low = (arr[4]<<24) | ((arr[5]&0xff)<<16) | ((arr[6]&0xff)<<8) | (arr[7]&0xff); - return (((long)high)<<32) | (low&0x0ffffffffL); - } - - public static float toFloat(byte[] arr) { - return Float.intBitsToFloat(toInt(arr)); - } - - public static double toDouble(byte[] arr) { - return Double.longBitsToDouble(toLong(arr)); - } - - public static byte[] toArr(int val) { - byte[] arr = new byte[4]; - arr[0] = (byte)(val>>>24); - arr[1] = (byte)(val>>>16); - arr[2] = (byte)(val>>>8); - arr[3] = (byte)(val); - return arr; - } - - public static byte[] toArr(long val) { - byte[] arr = new byte[8]; - arr[0] = (byte)(val>>>56); - arr[1] = (byte)(val>>>48); - arr[2] = (byte)(val>>>40); - arr[3] = (byte)(val>>>32); - arr[4] = (byte)(val>>>24); - arr[5] = (byte)(val>>>16); - arr[6] = (byte)(val>>>8); - arr[7] = (byte)(val); - return arr; - } - - public static byte[] toArr(float val) { - return toArr(Float.floatToRawIntBits(val)); - } - - public static byte[] toArr(double val) { - return toArr(Double.doubleToRawLongBits(val)); - } -} diff --git a/solr/src/java/org/apache/solr/update/AddUpdateCommand.java b/solr/src/java/org/apache/solr/update/AddUpdateCommand.java index 84632ee0b39..6a02010bf43 100644 --- a/solr/src/java/org/apache/solr/update/AddUpdateCommand.java +++ b/solr/src/java/org/apache/solr/update/AddUpdateCommand.java @@ -18,7 +18,7 @@ package org.apache.solr.update; import org.apache.lucene.document.Document; -import org.apache.lucene.document.Field; +import org.apache.lucene.document.Fieldable; import org.apache.lucene.index.Term; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.SolrInputField; @@ -74,7 +74,7 @@ public class AddUpdateCommand extends UpdateCommand { if (sf != null) { if (doc != null) { schema.getUniqueKeyField(); - Field storedId = doc.getField(sf.getName()); + Fieldable storedId = doc.getFieldable(sf.getName()); indexedId = sf.getType().storedToIndexed(storedId); } if (solrDoc != null) { diff --git a/solr/src/java/org/apache/solr/update/DocumentBuilder.java b/solr/src/java/org/apache/solr/update/DocumentBuilder.java index e78e18d3340..a7b80e0ded8 100644 --- a/solr/src/java/org/apache/solr/update/DocumentBuilder.java +++ b/solr/src/java/org/apache/solr/update/DocumentBuilder.java @@ -159,7 +159,7 @@ public class DocumentBuilder { // default value are defacto 'required' fields. List missingFields = null; for (SchemaField field : schema.getRequiredFields()) { - if (doc.getField(field.getName() ) == null) { + if (doc.getFieldable(field.getName() ) == null) { if (field.getDefaultValue() != null) { addField(doc, field, field.getDefaultValue(), 1.0f); } else { @@ -313,7 +313,7 @@ public class DocumentBuilder { // Now validate required fields or add default values // fields with default values are defacto 'required' for (SchemaField field : schema.getRequiredFields()) { - if (out.getField(field.getName() ) == null) { + if (out.getFieldable(field.getName() ) == null) { if (field.getDefaultValue() != null) { addField(out, field, field.getDefaultValue(), 1.0f); } @@ -339,8 +339,7 @@ public class DocumentBuilder { */ public SolrDocument loadStoredFields( SolrDocument doc, Document luceneDoc ) { - for( Object f : luceneDoc.getFields() ) { - Fieldable field = (Fieldable)f; + for( Fieldable field : luceneDoc.getFields() ) { if( field.isStored() ) { SchemaField sf = schema.getField( field.name() ); if( !schema.isCopyFieldTarget( sf ) ) { diff --git a/solr/src/java/org/apache/solr/update/UpdateHandler.java b/solr/src/java/org/apache/solr/update/UpdateHandler.java index e7332349dfd..cd13a4935ab 100644 --- a/solr/src/java/org/apache/solr/update/UpdateHandler.java +++ b/solr/src/java/org/apache/solr/update/UpdateHandler.java @@ -21,7 +21,6 @@ package org.apache.solr.update; import org.apache.lucene.index.IndexReader.AtomicReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.document.Document; -import org.apache.lucene.document.Field; import org.apache.lucene.document.Fieldable; import org.apache.lucene.search.Collector; import org.apache.lucene.search.Scorer; @@ -125,7 +124,7 @@ public abstract class UpdateHandler implements SolrInfoMBean { protected final String getIndexedIdOptional(Document doc) { if (idField == null) return null; - Field f = doc.getField(idField.getName()); + Fieldable f = doc.getFieldable(idField.getName()); if (f == null) return null; return idFieldType.storedToIndexed(f); } diff --git a/solr/src/test/org/apache/solr/BasicFunctionalityTest.java b/solr/src/test/org/apache/solr/BasicFunctionalityTest.java index f19d9b2b8c0..3b12f7978e4 100644 --- a/solr/src/test/org/apache/solr/BasicFunctionalityTest.java +++ b/solr/src/test/org/apache/solr/BasicFunctionalityTest.java @@ -561,7 +561,7 @@ public class BasicFunctionalityTest extends SolrTestCaseJ4 { DocList dl = ((ResultContext) rsp.getValues().get("response")).docs; org.apache.lucene.document.Document d = req.getSearcher().doc(dl.iterator().nextDoc()); - // ensure field is not lazy + // ensure field is not lazy, only works for Non-Numeric fields currently (if you change schema behind test, this may fail) assertTrue( d.getFieldable("test_hlt") instanceof Field ); assertTrue( d.getFieldable("title") instanceof Field ); req.close(); diff --git a/solr/src/test/org/apache/solr/handler/MoreLikeThisHandlerTest.java b/solr/src/test/org/apache/solr/handler/MoreLikeThisHandlerTest.java index 6dbae21f244..c7d8a392201 100644 --- a/solr/src/test/org/apache/solr/handler/MoreLikeThisHandlerTest.java +++ b/solr/src/test/org/apache/solr/handler/MoreLikeThisHandlerTest.java @@ -79,7 +79,7 @@ public class MoreLikeThisHandlerTest extends SolrTestCaseJ4 { params.set(CommonParams.Q, "id:42"); params.set(MoreLikeThisParams.MLT, "true"); - params.set(MoreLikeThisParams.SIMILARITY_FIELDS, "name,subword,foo_ti"); + params.set(MoreLikeThisParams.SIMILARITY_FIELDS, "name,subword"); params.set(MoreLikeThisParams.INTERESTING_TERMS, "details"); params.set(MoreLikeThisParams.MIN_TERM_FREQ,"1"); params.set(MoreLikeThisParams.MIN_DOC_FREQ,"1"); diff --git a/solr/src/test/org/apache/solr/update/DocumentBuilderTest.java b/solr/src/test/org/apache/solr/update/DocumentBuilderTest.java index 4a4df13b0f7..991295d1339 100644 --- a/solr/src/test/org/apache/solr/update/DocumentBuilderTest.java +++ b/solr/src/test/org/apache/solr/update/DocumentBuilderTest.java @@ -109,8 +109,8 @@ public class DocumentBuilderTest extends SolrTestCaseJ4 { doc.addField( "home", "2.2,3.3", 1.0f ); Document out = DocumentBuilder.toDocument( doc, core.getSchema() ); assertNotNull( out.get( "home" ) );//contains the stored value and term vector, if there is one - assertNotNull( out.getField( "home_0" + FieldType.POLY_FIELD_SEPARATOR + "double" ) ); - assertNotNull( out.getField( "home_1" + FieldType.POLY_FIELD_SEPARATOR + "double" ) ); + assertNotNull( out.getFieldable( "home_0" + FieldType.POLY_FIELD_SEPARATOR + "double" ) ); + assertNotNull( out.getFieldable( "home_1" + FieldType.POLY_FIELD_SEPARATOR + "double" ) ); } } From 1d842018fcb6785c6d647dd8e7b69f97cb60885d Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Mon, 9 May 2011 06:41:09 +0000 Subject: [PATCH 34/57] LUCENE-3077: DWPT doesn't see changes to DW#infoStream git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1100896 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/java/org/apache/lucene/index/DocumentsWriter.java | 2 +- .../org/apache/lucene/index/DocumentsWriterPerThread.java | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/index/DocumentsWriter.java b/lucene/src/java/org/apache/lucene/index/DocumentsWriter.java index 5e316c21fee..d148b4cbdda 100644 --- a/lucene/src/java/org/apache/lucene/index/DocumentsWriter.java +++ b/lucene/src/java/org/apache/lucene/index/DocumentsWriter.java @@ -188,7 +188,7 @@ final class DocumentsWriter { this.infoStream = infoStream; final Iterator it = perThreadPool.getAllPerThreadsIterator(); while (it.hasNext()) { - it.next().perThread.docState.infoStream = infoStream; + it.next().perThread.setInfoStream(infoStream); } } diff --git a/lucene/src/java/org/apache/lucene/index/DocumentsWriterPerThread.java b/lucene/src/java/org/apache/lucene/index/DocumentsWriterPerThread.java index 4ffb1e0ccf7..f2dffe8fc62 100644 --- a/lucene/src/java/org/apache/lucene/index/DocumentsWriterPerThread.java +++ b/lucene/src/java/org/apache/lucene/index/DocumentsWriterPerThread.java @@ -163,7 +163,7 @@ public class DocumentsWriterPerThread { boolean hasAborted = false; // True if the last exception throws by #updateDocument was aborting private FieldInfos fieldInfos; - private final PrintStream infoStream; + private PrintStream infoStream; private int numDocsInRAM; private int flushedDocCount; DocumentsWriterDeleteQueue deleteQueue; @@ -493,4 +493,9 @@ public class DocumentsWriterPerThread { } }; + + void setInfoStream(PrintStream infoStream) { + this.infoStream = infoStream; + docState.infoStream = infoStream; + } } From b30e4e4ec89dd82d910923ff8968d5f21cca266c Mon Sep 17 00:00:00 2001 From: Koji Sekiguchi Date: Mon, 9 May 2011 14:56:01 +0000 Subject: [PATCH 35/57] SOLR-2503: feature value map to dynamicField git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1101047 13f79535-47bb-0310-9956-ffa450edef68 --- solr/contrib/uima/CHANGES.txt | 5 ++ .../uima/processor/SolrUIMAConfiguration.java | 41 +++++++++++++-- .../SolrUIMAConfigurationReader.java | 17 +++++-- .../solr/uima/processor/UIMAToSolrMapper.java | 9 +++- .../processor/UIMAUpdateRequestProcessor.java | 3 +- .../UIMAUpdateRequestProcessorTest.java | 13 ++--- .../processor/an/DummyEntityAnnotator.java | 6 +++ .../apache/solr/uima/ts/EntityAnnotation.java | 44 ++++++++++++++-- .../solr/uima/ts/EntityAnnotation_Type.java | 50 ++++++++++++++++++- .../resources/DummyEntityAEDescriptor.xml | 12 +++++ .../test/resources/solr-uima/conf/schema.xml | 1 + .../resources/solr-uima/conf/solrconfig.xml | 5 +- 12 files changed, 182 insertions(+), 24 deletions(-) diff --git a/solr/contrib/uima/CHANGES.txt b/solr/contrib/uima/CHANGES.txt index a31054a05b5..6e97c775acb 100644 --- a/solr/contrib/uima/CHANGES.txt +++ b/solr/contrib/uima/CHANGES.txt @@ -28,6 +28,11 @@ Upgrading from Solr 3.1 It should move to UIMAUpdateRequestProcessorFactory setting. See contrib/uima/README.txt for more details. (SOLR-2436) +New Features +---------------------- + +* SOLR-2503: extend mapping function to map feature value to dynamicField. (koji) + Test Cases: ---------------------- diff --git a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfiguration.java b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfiguration.java index 22357262ba3..68c9e1bac0a 100644 --- a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfiguration.java +++ b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfiguration.java @@ -30,14 +30,14 @@ public class SolrUIMAConfiguration { private boolean fieldsMerging; - private Map> typesFeaturesFieldsMapping; + private Map> typesFeaturesFieldsMapping; private String aePath; private Map runtimeParameters; public SolrUIMAConfiguration(String aePath, String[] fieldsToAnalyze, boolean fieldsMerging, - Map> typesFeaturesFieldsMapping, + Map> typesFeaturesFieldsMapping, Map runtimeParameters) { this.aePath = aePath; this.fieldsToAnalyze = fieldsToAnalyze; @@ -54,7 +54,7 @@ public class SolrUIMAConfiguration { return fieldsMerging; } - public Map> getTypesFeaturesFieldsMapping() { + public Map> getTypesFeaturesFieldsMapping() { return typesFeaturesFieldsMapping; } @@ -65,4 +65,39 @@ public class SolrUIMAConfiguration { public Map getRuntimeParameters() { return runtimeParameters; } + + static final class MapField { + + private String fieldName, fieldNameFeature; + private boolean prefix; // valid if dynamicField == true + // false: *_s, true: s_* + + MapField(String fieldName, String fieldNameFeature){ + this.fieldName = fieldName; + this.fieldNameFeature = fieldNameFeature; + if(fieldNameFeature != null){ + if(fieldName.startsWith("*")){ + prefix = false; + this.fieldName = fieldName.substring(1); + } + else if(fieldName.endsWith("*")){ + prefix = true; + this.fieldName = fieldName.substring(0, fieldName.length() - 1); + } + else + throw new RuntimeException("static field name cannot be used for dynamicField"); + } + } + + String getFieldNameFeature(){ + return fieldNameFeature; + } + + String getFieldName(String featureValue){ + if(fieldNameFeature != null){ + return prefix ? fieldName + featureValue : featureValue + fieldName; + } + return fieldName; + } + } } diff --git a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfigurationReader.java b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfigurationReader.java index f540a6417f0..fc225d1deba 100644 --- a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfigurationReader.java +++ b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/SolrUIMAConfigurationReader.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Map; import org.apache.solr.common.util.NamedList; +import org.apache.solr.uima.processor.SolrUIMAConfiguration.MapField; /** * Read configuration for Solr-UIMA integration @@ -62,8 +63,8 @@ public class SolrUIMAConfigurationReader { } @SuppressWarnings("rawtypes") - private Map> readTypesFeaturesFieldsMapping() { - Map> map = new HashMap>(); + private Map> readTypesFeaturesFieldsMapping() { + Map> map = new HashMap>(); NamedList fieldMappings = (NamedList) args.get("fieldMappings"); /* iterate over UIMA types */ @@ -71,13 +72,21 @@ public class SolrUIMAConfigurationReader { NamedList type = (NamedList) fieldMappings.get("type", i); String typeName = (String)type.get("name"); - Map subMap = new HashMap(); + Map subMap = new HashMap(); /* iterate over mapping definitions */ for(int j = 0; j < type.size() - 1; j++){ NamedList mapping = (NamedList) type.get("mapping", j + 1); String featureName = (String) mapping.get("feature"); + String fieldNameFeature = null; String mappedFieldName = (String) mapping.get("field"); - subMap.put(featureName, mappedFieldName); + if(mappedFieldName == null){ + fieldNameFeature = (String) mapping.get("fieldNameFeature"); + mappedFieldName = (String) mapping.get("dynamicField"); + } + if(mappedFieldName == null) + throw new RuntimeException("either of field or dynamicField should be defined for feature " + featureName); + MapField mapField = new MapField(mappedFieldName, fieldNameFeature); + subMap.put(featureName, mapField); } map.put(typeName, subMap); } diff --git a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAToSolrMapper.java b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAToSolrMapper.java index 29e7b5c2926..6d8cdc50c0d 100644 --- a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAToSolrMapper.java +++ b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAToSolrMapper.java @@ -20,6 +20,7 @@ package org.apache.solr.uima.processor; import java.util.Map; import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.uima.processor.SolrUIMAConfiguration.MapField; import org.apache.uima.cas.FSIterator; import org.apache.uima.cas.FeatureStructure; import org.apache.uima.cas.Type; @@ -53,7 +54,7 @@ public class UIMAToSolrMapper { * name of UIMA type to map * @param featureFieldsmapping */ - public void map(String typeName, Map featureFieldsmapping) { + public void map(String typeName, Map featureFieldsmapping) { try { FeatureStructure fsMock = (FeatureStructure) Class.forName(typeName).getConstructor( JCas.class).newInstance(cas); @@ -62,7 +63,11 @@ public class UIMAToSolrMapper { .hasNext();) { FeatureStructure fs = iterator.next(); for (String featureName : featureFieldsmapping.keySet()) { - String fieldName = featureFieldsmapping.get(featureName); + MapField mapField = featureFieldsmapping.get(featureName); + String fieldNameFeature = mapField.getFieldNameFeature(); + String fieldNameFeatureValue = fieldNameFeature == null ? null : + fs.getFeatureValueAsString(type.getFeatureByBaseName(fieldNameFeature)); + String fieldName = mapField.getFieldName(fieldNameFeatureValue); log.info(new StringBuffer("mapping ").append(typeName).append("@").append(featureName) .append(" to ").append(fieldName).toString()); String featureValue = null; diff --git a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessor.java b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessor.java index 6994a5e3522..9950838569c 100644 --- a/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessor.java +++ b/solr/contrib/uima/src/main/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessor.java @@ -22,6 +22,7 @@ import java.util.Map; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.core.SolrCore; +import org.apache.solr.uima.processor.SolrUIMAConfiguration.MapField; import org.apache.solr.uima.processor.ae.AEProvider; import org.apache.solr.uima.processor.ae.AEProviderFactory; import org.apache.solr.update.AddUpdateCommand; @@ -69,7 +70,7 @@ public class UIMAUpdateRequestProcessor extends UpdateRequestProcessor { UIMAToSolrMapper uimaToSolrMapper = new UIMAToSolrMapper(solrInputDocument, jcas); /* get field mapping from config */ - Map> typesAndFeaturesFieldsMap = solrUIMAConfiguration + Map> typesAndFeaturesFieldsMap = solrUIMAConfiguration .getTypesFeaturesFieldsMapping(); /* map type features on fields */ for (String typeFQN : typesAndFeaturesFieldsMap.keySet()) { diff --git a/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessorTest.java b/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessorTest.java index 0e2d5147215..c7275829171 100644 --- a/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessorTest.java +++ b/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/UIMAUpdateRequestProcessorTest.java @@ -33,6 +33,7 @@ import org.apache.solr.core.SolrCore; import org.apache.solr.handler.XmlUpdateRequestHandler; import org.apache.solr.request.SolrQueryRequestBase; import org.apache.solr.response.SolrQueryResponse; +import org.apache.solr.uima.processor.SolrUIMAConfiguration.MapField; import org.apache.solr.update.processor.UpdateRequestProcessor; import org.apache.solr.update.processor.UpdateRequestProcessorChain; import org.junit.Before; @@ -82,11 +83,11 @@ public class UIMAUpdateRequestProcessorTest extends SolrTestCaseJ4 { UpdateRequestProcessor processor = factory.getInstance(req(), null, null); assertTrue(processor instanceof UIMAUpdateRequestProcessor); SolrUIMAConfiguration conf = ((UIMAUpdateRequestProcessor)processor).solrUIMAConfiguration; - Map> map = conf.getTypesFeaturesFieldsMapping(); - Map subMap = map.get("a-type-which-can-have-multiple-features"); + Map> map = conf.getTypesFeaturesFieldsMapping(); + Map subMap = map.get("a-type-which-can-have-multiple-features"); assertEquals(2, subMap.size()); - assertEquals("1", subMap.get("A")); - assertEquals("2", subMap.get("B")); + assertEquals("1", subMap.get("A").getFieldName(null)); + assertEquals("2", subMap.get("B").getFieldName(null)); } @Test @@ -104,7 +105,7 @@ public class UIMAUpdateRequestProcessorTest extends SolrTestCaseJ4 { assertU(commit()); assertQ(req("sentence:*"), "//*[@numFound='1']"); assertQ(req("sentiment:*"), "//*[@numFound='0']"); - assertQ(req("entity:Prague"), "//*[@numFound='1']"); + assertQ(req("OTHER_sm:Prague"), "//*[@numFound='1']"); } @Test @@ -124,7 +125,7 @@ public class UIMAUpdateRequestProcessorTest extends SolrTestCaseJ4 { assertQ(req("sentence:*"), "//*[@numFound='2']"); assertQ(req("sentiment:positive"), "//*[@numFound='1']"); - assertQ(req("entity:Apache"), "//*[@numFound='2']"); + assertQ(req("ORGANIZATION_sm:Apache"), "//*[@numFound='2']"); } private void addDoc(String doc) throws Exception { diff --git a/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/an/DummyEntityAnnotator.java b/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/an/DummyEntityAnnotator.java index 6c3941ac49e..e59da1228fe 100644 --- a/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/an/DummyEntityAnnotator.java +++ b/solr/contrib/uima/src/test/java/org/apache/solr/uima/processor/an/DummyEntityAnnotator.java @@ -34,6 +34,12 @@ public class DummyEntityAnnotator extends JCasAnnotator_ImplBase{ EntityAnnotation entityAnnotation = new EntityAnnotation(jcas); entityAnnotation.setBegin(annotation.getBegin()); entityAnnotation.setEnd(annotation.getEnd()); + String entityString = annotation.getCoveredText(); + entityAnnotation.setEntity(entityString); + String name = "OTHER"; // "OTHER" makes no sense. In practice, "PERSON", "COUNTRY", "E-MAIL", etc. + if(entityString.equals("Apache")) + name = "ORGANIZATION"; + entityAnnotation.setName(name); entityAnnotation.addToIndexes(); } } diff --git a/solr/contrib/uima/src/test/java/org/apache/solr/uima/ts/EntityAnnotation.java b/solr/contrib/uima/src/test/java/org/apache/solr/uima/ts/EntityAnnotation.java index f48e5bc0912..ed597514a71 100644 --- a/solr/contrib/uima/src/test/java/org/apache/solr/uima/ts/EntityAnnotation.java +++ b/solr/contrib/uima/src/test/java/org/apache/solr/uima/ts/EntityAnnotation.java @@ -1,6 +1,6 @@ -/* First created by JCasGen Fri Mar 04 12:48:08 CET 2011 */ +/* First created by JCasGen Sat May 07 22:33:38 JST 2011 */ package org.apache.solr.uima.ts; import org.apache.uima.jcas.JCas; @@ -11,8 +11,8 @@ import org.apache.uima.jcas.tcas.Annotation; /** - * Updated by JCasGen Fri Mar 04 12:50:14 CET 2011 - * XML source: /Users/tommasoteofili/Documents/workspaces/lucene_workspace/lucene_dev/solr/contrib/uima/src/test/resources/DummyEntityAEDescriptor.xml + * Updated by JCasGen Sat May 07 22:33:38 JST 2011 + * XML source: /Users/koji/Documents/workspace/DummyEntityAnnotator/desc/DummyEntityAEDescriptor.xml * @generated */ public class EntityAnnotation extends Annotation { /** @generated @@ -57,6 +57,42 @@ public class EntityAnnotation extends Annotation { @generated modifiable */ private void readObject() {} -} + + + //*--------------* + //* Feature: name + + /** getter for name - gets + * @generated */ + public String getName() { + if (EntityAnnotation_Type.featOkTst && ((EntityAnnotation_Type)jcasType).casFeat_name == null) + jcasType.jcas.throwFeatMissing("name", "org.apache.solr.uima.ts.EntityAnnotation"); + return jcasType.ll_cas.ll_getStringValue(addr, ((EntityAnnotation_Type)jcasType).casFeatCode_name);} + + /** setter for name - sets + * @generated */ + public void setName(String v) { + if (EntityAnnotation_Type.featOkTst && ((EntityAnnotation_Type)jcasType).casFeat_name == null) + jcasType.jcas.throwFeatMissing("name", "org.apache.solr.uima.ts.EntityAnnotation"); + jcasType.ll_cas.ll_setStringValue(addr, ((EntityAnnotation_Type)jcasType).casFeatCode_name, v);} + + + //*--------------* + //* Feature: entity + + /** getter for entity - gets + * @generated */ + public String getEntity() { + if (EntityAnnotation_Type.featOkTst && ((EntityAnnotation_Type)jcasType).casFeat_entity == null) + jcasType.jcas.throwFeatMissing("entity", "org.apache.solr.uima.ts.EntityAnnotation"); + return jcasType.ll_cas.ll_getStringValue(addr, ((EntityAnnotation_Type)jcasType).casFeatCode_entity);} + + /** setter for entity - sets + * @generated */ + public void setEntity(String v) { + if (EntityAnnotation_Type.featOkTst && ((EntityAnnotation_Type)jcasType).casFeat_entity == null) + jcasType.jcas.throwFeatMissing("entity", "org.apache.solr.uima.ts.EntityAnnotation"); + jcasType.ll_cas.ll_setStringValue(addr, ((EntityAnnotation_Type)jcasType).casFeatCode_entity, v);} + } \ No newline at end of file diff --git a/solr/contrib/uima/src/test/java/org/apache/solr/uima/ts/EntityAnnotation_Type.java b/solr/contrib/uima/src/test/java/org/apache/solr/uima/ts/EntityAnnotation_Type.java index f7bb572f7aa..5be6a1a6020 100644 --- a/solr/contrib/uima/src/test/java/org/apache/solr/uima/ts/EntityAnnotation_Type.java +++ b/solr/contrib/uima/src/test/java/org/apache/solr/uima/ts/EntityAnnotation_Type.java @@ -1,5 +1,5 @@ -/* First created by JCasGen Fri Mar 04 12:48:08 CET 2011 */ +/* First created by JCasGen Sat May 07 22:33:38 JST 2011 */ package org.apache.solr.uima.ts; import org.apache.uima.jcas.JCas; @@ -9,10 +9,12 @@ import org.apache.uima.cas.impl.FSGenerator; import org.apache.uima.cas.FeatureStructure; import org.apache.uima.cas.impl.TypeImpl; import org.apache.uima.cas.Type; +import org.apache.uima.cas.impl.FeatureImpl; +import org.apache.uima.cas.Feature; import org.apache.uima.jcas.tcas.Annotation_Type; /** - * Updated by JCasGen Fri Mar 04 12:50:14 CET 2011 + * Updated by JCasGen Sat May 07 22:33:38 JST 2011 * @generated */ public class EntityAnnotation_Type extends Annotation_Type { /** @generated */ @@ -38,6 +40,42 @@ public class EntityAnnotation_Type extends Annotation_Type { /** @generated @modifiable */ public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.solr.uima.ts.EntityAnnotation"); + + /** @generated */ + final Feature casFeat_name; + /** @generated */ + final int casFeatCode_name; + /** @generated */ + public String getName(int addr) { + if (featOkTst && casFeat_name == null) + jcas.throwFeatMissing("name", "org.apache.solr.uima.ts.EntityAnnotation"); + return ll_cas.ll_getStringValue(addr, casFeatCode_name); + } + /** @generated */ + public void setName(int addr, String v) { + if (featOkTst && casFeat_name == null) + jcas.throwFeatMissing("name", "org.apache.solr.uima.ts.EntityAnnotation"); + ll_cas.ll_setStringValue(addr, casFeatCode_name, v);} + + + + /** @generated */ + final Feature casFeat_entity; + /** @generated */ + final int casFeatCode_entity; + /** @generated */ + public String getEntity(int addr) { + if (featOkTst && casFeat_entity == null) + jcas.throwFeatMissing("entity", "org.apache.solr.uima.ts.EntityAnnotation"); + return ll_cas.ll_getStringValue(addr, casFeatCode_entity); + } + /** @generated */ + public void setEntity(int addr, String v) { + if (featOkTst && casFeat_entity == null) + jcas.throwFeatMissing("entity", "org.apache.solr.uima.ts.EntityAnnotation"); + ll_cas.ll_setStringValue(addr, casFeatCode_entity, v);} + + @@ -47,6 +85,14 @@ public class EntityAnnotation_Type extends Annotation_Type { super(jcas, casType); casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl)this.casType, getFSGenerator()); + + casFeat_name = jcas.getRequiredFeatureDE(casType, "name", "uima.cas.String", featOkTst); + casFeatCode_name = (null == casFeat_name) ? JCas.INVALID_FEATURE_CODE : ((FeatureImpl)casFeat_name).getCode(); + + + casFeat_entity = jcas.getRequiredFeatureDE(casType, "entity", "uima.cas.String", featOkTst); + casFeatCode_entity = (null == casFeat_entity) ? JCas.INVALID_FEATURE_CODE : ((FeatureImpl)casFeat_entity).getCode(); + } } diff --git a/solr/contrib/uima/src/test/resources/DummyEntityAEDescriptor.xml b/solr/contrib/uima/src/test/resources/DummyEntityAEDescriptor.xml index 61f1d8c8046..33f05e50e39 100644 --- a/solr/contrib/uima/src/test/resources/DummyEntityAEDescriptor.xml +++ b/solr/contrib/uima/src/test/resources/DummyEntityAEDescriptor.xml @@ -32,6 +32,18 @@ org.apache.solr.uima.ts.EntityAnnotation uima.tcas.Annotation + + + name + + uima.cas.String + + + entity + + uima.cas.String + + diff --git a/solr/contrib/uima/src/test/resources/solr-uima/conf/schema.xml b/solr/contrib/uima/src/test/resources/solr-uima/conf/schema.xml index 6df09b51320..85d15ef77f1 100644 --- a/solr/contrib/uima/src/test/resources/solr-uima/conf/schema.xml +++ b/solr/contrib/uima/src/test/resources/solr-uima/conf/schema.xml @@ -597,6 +597,7 @@ stored="true" multiValued="true"/> --> + + samsung electronics hard drive 7200RPM, 8MB cache, IDE Ultra ATA-133 @@ -36,6 +38,8 @@ 6H500F0 Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300 Maxtor Corp. + + maxtor electronics hard drive SATA 3.0Gb/s, NCQ diff --git a/solr/example/exampledocs/ipod_other.xml b/solr/example/exampledocs/ipod_other.xml index f259e9e7b43..7756c9fc805 100644 --- a/solr/example/exampledocs/ipod_other.xml +++ b/solr/example/exampledocs/ipod_other.xml @@ -21,6 +21,8 @@ F8V7067-APL-KIT Belkin Mobile Power Cord for iPod w/ Dock Belkin + + belkin electronics connector car power adapter, white @@ -37,6 +39,8 @@ IW-02 iPod & iPod Mini USB 2.0 Cable Belkin + + belkin electronics connector car power adapter for iPod, white diff --git a/solr/example/exampledocs/ipod_video.xml b/solr/example/exampledocs/ipod_video.xml index 7895860ea19..1ca5f6f5c21 100644 --- a/solr/example/exampledocs/ipod_video.xml +++ b/solr/example/exampledocs/ipod_video.xml @@ -19,6 +19,8 @@ MA147LL/A Apple 60 GB iPod with Video Playback Black Apple Computer Inc. + + apple electronics music iTunes, Podcasts, Audiobooks diff --git a/solr/example/exampledocs/manufacturers.xml b/solr/example/exampledocs/manufacturers.xml new file mode 100644 index 00000000000..5e7a121394a --- /dev/null +++ b/solr/example/exampledocs/manufacturers.xml @@ -0,0 +1,75 @@ + + + + + adata + A-Data Technology + 46221 Landing Parkway Fremont, CA 94538 + + + apple + Apple + 1 Infinite Way, Cupertino CA + + + asus + ASUS Computer + 800 Corporate Way Fremont, CA 94539 + + + ati + ATI Technologies + 33 Commerce Valley Drive East Thornhill, ON L3T 7N6 Canada + + + belkin + Belkin + 12045 E. Waterfront Drive Playa Vista, CA 90094 + + + canon + Canon, Inc. + One Canon Plaza Lake Success, NY 11042 + + + corsair + Corsair Microsystems + 46221 Landing Parkway Fremont, CA 94538 + + + dell + Dell, Inc. + One Dell Way Round Rock, Texas 78682 + + + maxtor + Maxtor Corporation + 920 Disc Drive Scotts Valley, CA 95066 + + + samsung + Samsung Electronics Co. Ltd. + 105 Challenger Rd. Ridgefield Park, NJ 07660-0511 + + + viewsonic + ViewSonic Corp + 381 Brea Canyon Road Walnut, CA 91789-0708 + + + diff --git a/solr/example/exampledocs/mem.xml b/solr/example/exampledocs/mem.xml index 1ca858d4a6b..0b89d6785c2 100644 --- a/solr/example/exampledocs/mem.xml +++ b/solr/example/exampledocs/mem.xml @@ -20,6 +20,8 @@ TWINX2048-3200PRO CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail Corsair Microsystems Inc. + + corsair electronics memory CAS latency 2, 2-3-3-6 timing, 2.75v, unbuffered, heat-spreader @@ -38,6 +40,8 @@ VS1GB400C3 CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail Corsair Microsystems Inc. + + corsair electronics memory 74.99 @@ -54,6 +58,8 @@ VDBDB1A16 A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM A-DATA Technology Inc. + + corsair electronics memory CAS latency 3, 2.7v diff --git a/solr/example/exampledocs/monitor.xml b/solr/example/exampledocs/monitor.xml index 035f61891da..db986fa0b7f 100644 --- a/solr/example/exampledocs/monitor.xml +++ b/solr/example/exampledocs/monitor.xml @@ -19,6 +19,8 @@ 3007WFP Dell Widescreen UltraSharp 3007WFP Dell, Inc. + + dell electronics monitor 30" TFT active matrix LCD, 2560 x 1600, .25mm dot pitch, 700:1 contrast diff --git a/solr/example/exampledocs/monitor2.xml b/solr/example/exampledocs/monitor2.xml index 09cc778c3da..79b99494319 100644 --- a/solr/example/exampledocs/monitor2.xml +++ b/solr/example/exampledocs/monitor2.xml @@ -19,6 +19,8 @@ VA902B ViewSonic VA902B - flat panel display - TFT - 19" ViewSonic Corp. + + viewsonic electronics monitor 19" TFT active matrix LCD, 8ms response time, 1280 x 1024 native resolution diff --git a/solr/example/exampledocs/mp500.xml b/solr/example/exampledocs/mp500.xml index 890cd4aadfb..bab401a289b 100644 --- a/solr/example/exampledocs/mp500.xml +++ b/solr/example/exampledocs/mp500.xml @@ -19,6 +19,8 @@ 0579B002 Canon PIXMA MP500 All-In-One Photo Printer Canon Inc. + + canon electronics multifunction printer printer diff --git a/solr/example/exampledocs/sd500.xml b/solr/example/exampledocs/sd500.xml index ff700025da8..145c6fd5de6 100644 --- a/solr/example/exampledocs/sd500.xml +++ b/solr/example/exampledocs/sd500.xml @@ -19,6 +19,8 @@ 9885A004 Canon PowerShot SD500 Canon Inc. + + canon electronics camera 3x zoop, 7.1 megapixel Digital ELPH diff --git a/solr/example/exampledocs/vidcard.xml b/solr/example/exampledocs/vidcard.xml index 9cd3fd1c79c..10b8121fdb1 100644 --- a/solr/example/exampledocs/vidcard.xml +++ b/solr/example/exampledocs/vidcard.xml @@ -19,7 +19,10 @@ EN7800GTX/2DHTV/256M ASUS Extreme N7800GTX/2DHTV (256 MB) + ASUS Computer Inc. + + asus electronics graphics card NVIDIA GeForce 7800 GTX GPU/VPU clocked at 486MHz @@ -39,6 +42,8 @@ 100-435805 ATI Radeon X1900 XTX 512 MB PCIE Video Card ATI Technologies + + ati electronics graphics card ATI RADEON X1900 GPU/VPU clocked at 650MHz From c58d788ab23620eab3270f39a29f84464d243799 Mon Sep 17 00:00:00 2001 From: Grant Ingersoll Date: Mon, 9 May 2011 18:30:14 +0000 Subject: [PATCH 42/57] SOLR-2384: add all fields info in debug mode git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1101136 13f79535-47bb-0310-9956-ffa450edef68 --- solr/example/solr/conf/velocity/doc.vm | 13 +++++++++++++ solr/example/solr/conf/velocity/footer.vm | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/solr/example/solr/conf/velocity/doc.vm b/solr/example/solr/conf/velocity/doc.vm index de3ad49aae2..91246389177 100644 --- a/solr/example/solr/conf/velocity/doc.vm +++ b/solr/example/solr/conf/velocity/doc.vm @@ -26,4 +26,17 @@ #if($params.getBool("debugQuery",false)) toggle explain

    $response.getExplainMap().get($doc.getFirstValue('id'))
    + toggle all fields + + #foreach($fieldname in $doc.fieldNames) +
    + $fieldname : + + #foreach($value in $doc.getFieldValues($fieldname)) + $value + #end + + #end +
    +
    #end \ No newline at end of file diff --git a/solr/example/solr/conf/velocity/footer.vm b/solr/example/solr/conf/velocity/footer.vm index 79c8f820afc..b55e8a5a618 100644 --- a/solr/example/solr/conf/velocity/footer.vm +++ b/solr/example/solr/conf/velocity/footer.vm @@ -4,7 +4,7 @@ #if($request.params.get('debugQuery')) disable debug #else - enable debug + enable debug #end #if($annotate) disable annotation From 9a34849ecccc031a034b9e8005e124fd6de70c97 Mon Sep 17 00:00:00 2001 From: Grant Ingersoll Date: Mon, 9 May 2011 19:25:46 +0000 Subject: [PATCH 43/57] SOLR-2502: missed compName git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1101159 13f79535-47bb-0310-9956-ffa450edef68 --- solr/example/exampledocs/manufacturers.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solr/example/exampledocs/manufacturers.xml b/solr/example/exampledocs/manufacturers.xml index 5e7a121394a..e3121d5db1f 100644 --- a/solr/example/exampledocs/manufacturers.xml +++ b/solr/example/exampledocs/manufacturers.xml @@ -58,7 +58,7 @@ maxtor - Maxtor Corporation + Maxtor Corporation 920 Disc Drive Scotts Valley, CA 95066 From 0394a540de574f0a31ff5f6835f49248e19a046b Mon Sep 17 00:00:00 2001 From: Steven Rowe Date: Tue, 10 May 2011 12:36:11 +0000 Subject: [PATCH 44/57] native eol style git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1101435 13f79535-47bb-0310-9956-ffa450edef68 From 303ff3928fe4ce6a48a072d1923d94e7a47a6bb5 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Tue, 10 May 2011 16:01:17 +0000 Subject: [PATCH 45/57] vary readBufferSize in MockRandomCodec git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1101520 13f79535-47bb-0310-9956-ffa450edef68 --- .../index/codecs/mockrandom/MockRandomCodec.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lucene/src/test-framework/org/apache/lucene/index/codecs/mockrandom/MockRandomCodec.java b/lucene/src/test-framework/org/apache/lucene/index/codecs/mockrandom/MockRandomCodec.java index 4e1c33eb95c..2fe6154bcf7 100644 --- a/lucene/src/test-framework/org/apache/lucene/index/codecs/mockrandom/MockRandomCodec.java +++ b/lucene/src/test-framework/org/apache/lucene/index/codecs/mockrandom/MockRandomCodec.java @@ -140,6 +140,9 @@ public class MockRandomCodec extends Codec { out.close(); final Random random = new Random(seed); + + random.nextInt(); // consume a random for buffersize + PostingsWriterBase postingsWriter; if (random.nextBoolean()) { @@ -238,16 +241,22 @@ public class MockRandomCodec extends Codec { in.close(); final Random random = new Random(seed); + + int readBufferSize = _TestUtil.nextInt(random, 1, 4096); + if (LuceneTestCase.VERBOSE) { + System.out.println("MockRandomCodec: readBufferSize=" + readBufferSize); + } + PostingsReaderBase postingsReader; if (random.nextBoolean()) { postingsReader = new SepPostingsReaderImpl(state.dir, state.segmentInfo, - state.readBufferSize, new MockIntStreamFactory(random), state.codecId); + readBufferSize, new MockIntStreamFactory(random), state.codecId); } else { if (LuceneTestCase.VERBOSE) { System.out.println("MockRandomCodec: reading Standard postings"); } - postingsReader = new StandardPostingsReader(state.dir, state.segmentInfo, state.readBufferSize, state.codecId); + postingsReader = new StandardPostingsReader(state.dir, state.segmentInfo, readBufferSize, state.codecId); } if (random.nextBoolean()) { @@ -312,7 +321,7 @@ public class MockRandomCodec extends Codec { state.fieldInfos, state.segmentInfo.name, postingsReader, - state.readBufferSize, + readBufferSize, termsCacheSize, state.codecId); success = true; From a7418eb2068380e787b90df6f64cce4ece2382d7 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Tue, 10 May 2011 16:45:57 +0000 Subject: [PATCH 46/57] MockDirectoryWrapper should randomly swap in ThrottledIndexOutput git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1101539 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/store/MockDirectoryWrapper.java | 28 +++++++++++++++++-- .../org/apache/lucene/index/Test2BTerms.java | 3 +- .../index/TestFlushByRamOrCountsPolicy.java | 3 +- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/lucene/src/test-framework/org/apache/lucene/store/MockDirectoryWrapper.java b/lucene/src/test-framework/org/apache/lucene/store/MockDirectoryWrapper.java index 17b62a6f94d..c7b0d036dd1 100644 --- a/lucene/src/test-framework/org/apache/lucene/store/MockDirectoryWrapper.java +++ b/lucene/src/test-framework/org/apache/lucene/store/MockDirectoryWrapper.java @@ -71,6 +71,7 @@ public class MockDirectoryWrapper extends Directory { Set openFilesForWrite = new HashSet(); volatile boolean crashed; private ThrottledIndexOutput throttledOutput; + private Throttling throttling = Throttling.SOMETIMES; // use this for tracking files for crash. // additionally: provides debugging information in case you leave one open @@ -104,6 +105,8 @@ public class MockDirectoryWrapper extends Directory { // called from different threads; else test failures may // not be reproducible from the original seed this.randomState = new Random(random.nextInt()); + this.throttledOutput = new ThrottledIndexOutput(ThrottledIndexOutput + .mBitsToBytes(40 + randomState.nextInt(10)), 5 + randomState.nextInt(5), null); init(); } @@ -117,8 +120,17 @@ public class MockDirectoryWrapper extends Directory { preventDoubleWrite = value; } - public void setThrottledIndexOutput(ThrottledIndexOutput throttledOutput) { - this.throttledOutput = throttledOutput; + public static enum Throttling { + /** always emulate a slow hard disk. could be very slow! */ + ALWAYS, + /** sometimes (2% of the time) emulate a slow hard disk. */ + SOMETIMES, + /** never throttle output */ + NEVER + }; + + public void setThrottling(Throttling throttling) { + this.throttling = throttling; } @Override @@ -354,7 +366,17 @@ public class MockDirectoryWrapper extends Directory { IndexOutput io = new MockIndexOutputWrapper(this, delegate.createOutput(name), name); openFileHandles.put(io, new RuntimeException("unclosed IndexOutput")); openFilesForWrite.add(name); - return throttledOutput == null ? io : throttledOutput.newFromDelegate(io); + + // throttling REALLY slows down tests, so don't do it very often for SOMETIMES. + if (throttling == Throttling.ALWAYS || + (throttling == Throttling.SOMETIMES && randomState.nextInt(50) == 0)) { + if (LuceneTestCase.VERBOSE) { + System.out.println("MockDirectoryWrapper: throttling indexOutput"); + } + return throttledOutput.newFromDelegate(io); + } else { + return io; + } } @Override diff --git a/lucene/src/test/org/apache/lucene/index/Test2BTerms.java b/lucene/src/test/org/apache/lucene/index/Test2BTerms.java index 25cf0c4d987..6fffc48664a 100644 --- a/lucene/src/test/org/apache/lucene/index/Test2BTerms.java +++ b/lucene/src/test/org/apache/lucene/index/Test2BTerms.java @@ -153,7 +153,8 @@ public class Test2BTerms extends LuceneTestCase { List savedTerms = null; - Directory dir = newFSDirectory(_TestUtil.getTempDir("2BTerms")); + MockDirectoryWrapper dir = newFSDirectory(_TestUtil.getTempDir("2BTerms")); + dir.setThrottling(MockDirectoryWrapper.Throttling.NEVER); //Directory dir = newFSDirectory(new File("/p/lucene/indices/2bindex")); if (true) { diff --git a/lucene/src/test/org/apache/lucene/index/TestFlushByRamOrCountsPolicy.java b/lucene/src/test/org/apache/lucene/index/TestFlushByRamOrCountsPolicy.java index 7eb72130d3f..c6d69079fcf 100644 --- a/lucene/src/test/org/apache/lucene/index/TestFlushByRamOrCountsPolicy.java +++ b/lucene/src/test/org/apache/lucene/index/TestFlushByRamOrCountsPolicy.java @@ -233,8 +233,7 @@ public class TestFlushByRamOrCountsPolicy extends LuceneTestCase { AtomicInteger numDocs = new AtomicInteger(numDocumentsToIndex); MockDirectoryWrapper dir = newDirectory(); // mock a very slow harddisk here so that flushing is very slow - dir.setThrottledIndexOutput(new ThrottledIndexOutput(ThrottledIndexOutput - .mBitsToBytes(40 + random.nextInt(10)), 5 + random.nextInt(5), null)); + dir.setThrottling(MockDirectoryWrapper.Throttling.ALWAYS); IndexWriterConfig iwc = newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)); iwc.setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH); From 673cef5639f3f7e8e8abe29cc940fe7ce0dff2e4 Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Tue, 10 May 2011 18:02:06 +0000 Subject: [PATCH 47/57] fix false test failure git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1101572 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/lucene/index/TestIndexWriter.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java b/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java index 90bf1cacc6d..e29ef531476 100644 --- a/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java +++ b/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java @@ -18,7 +18,6 @@ package org.apache.lucene.index; */ import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.io.Reader; @@ -1130,10 +1129,12 @@ public class TestIndexWriter extends LuceneTestCase { while(true) { MergePolicy.OneMerge merge = writer.getNextMerge(); - if (merge == null) + if (merge == null) { break; - for(int i=0;i Date: Tue, 10 May 2011 18:07:01 +0000 Subject: [PATCH 48/57] LUCENE-3084: cutover to List not SegmentInfos for MergePolicy.OneMerge.segments git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1101574 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/index/BufferedDeletesStream.java | 14 ++++----- .../index/ConcurrentMergeScheduler.java | 4 +-- .../org/apache/lucene/index/IndexWriter.java | 18 ++++++------ .../apache/lucene/index/LogMergePolicy.java | 3 +- .../lucene/index/MergeDocIDRemapper.java | 8 ++--- .../org/apache/lucene/index/MergePolicy.java | 12 ++++++-- .../lucene/index/TieredMergePolicy.java | 29 ++++++++++--------- .../lucene/index/UpgradeIndexMergePolicy.java | 4 ++- .../lucene/index/MockRandomMergePolicy.java | 6 ++-- 9 files changed, 55 insertions(+), 43 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/index/BufferedDeletesStream.java b/lucene/src/java/org/apache/lucene/index/BufferedDeletesStream.java index 11e55734046..745117daec0 100644 --- a/lucene/src/java/org/apache/lucene/index/BufferedDeletesStream.java +++ b/lucene/src/java/org/apache/lucene/index/BufferedDeletesStream.java @@ -132,9 +132,9 @@ class BufferedDeletesStream { public final long gen; // If non-null, contains segments that are 100% deleted - public final SegmentInfos allDeleted; + public final List allDeleted; - ApplyDeletesResult(boolean anyDeletes, long gen, SegmentInfos allDeleted) { + ApplyDeletesResult(boolean anyDeletes, long gen, List allDeleted) { this.anyDeletes = anyDeletes; this.gen = gen; this.allDeleted = allDeleted; @@ -164,7 +164,7 @@ class BufferedDeletesStream { /** Resolves the buffered deleted Term/Query/docIDs, into * actual deleted docIDs in the deletedDocs BitVector for * each SegmentReader. */ - public synchronized ApplyDeletesResult applyDeletes(IndexWriter.ReaderPool readerPool, SegmentInfos infos) throws IOException { + public synchronized ApplyDeletesResult applyDeletes(IndexWriter.ReaderPool readerPool, List infos) throws IOException { final long t0 = System.currentTimeMillis(); if (infos.size() == 0) { @@ -182,7 +182,7 @@ class BufferedDeletesStream { message("applyDeletes: infos=" + infos + " packetCount=" + deletes.size()); } - SegmentInfos infos2 = new SegmentInfos(); + List infos2 = new ArrayList(); infos2.addAll(infos); Collections.sort(infos2, sortSegInfoByDelGen); @@ -192,7 +192,7 @@ class BufferedDeletesStream { int infosIDX = infos2.size()-1; int delIDX = deletes.size()-1; - SegmentInfos allDeleted = null; + List allDeleted = null; while (infosIDX >= 0) { //System.out.println("BD: cycle delIDX=" + delIDX + " infoIDX=" + infosIDX); @@ -245,7 +245,7 @@ class BufferedDeletesStream { if (segAllDeletes) { if (allDeleted == null) { - allDeleted = new SegmentInfos(); + allDeleted = new ArrayList(); } allDeleted.add(info); } @@ -287,7 +287,7 @@ class BufferedDeletesStream { if (segAllDeletes) { if (allDeleted == null) { - allDeleted = new SegmentInfos(); + allDeleted = new ArrayList(); } allDeleted.add(info); } diff --git a/lucene/src/java/org/apache/lucene/index/ConcurrentMergeScheduler.java b/lucene/src/java/org/apache/lucene/index/ConcurrentMergeScheduler.java index b9cafc7c5c2..bc29b35c241 100644 --- a/lucene/src/java/org/apache/lucene/index/ConcurrentMergeScheduler.java +++ b/lucene/src/java/org/apache/lucene/index/ConcurrentMergeScheduler.java @@ -135,8 +135,8 @@ public class ConcurrentMergeScheduler extends MergeScheduler { final MergePolicy.OneMerge m1 = t1.getCurrentMerge(); final MergePolicy.OneMerge m2 = t2.getCurrentMerge(); - final int c1 = m1 == null ? Integer.MAX_VALUE : m1.segments.totalDocCount(); - final int c2 = m2 == null ? Integer.MAX_VALUE : m2.segments.totalDocCount(); + final int c1 = m1 == null ? Integer.MAX_VALUE : m1.totalDocCount; + final int c2 = m2 == null ? Integer.MAX_VALUE : m2.totalDocCount; return c2 - c1; } diff --git a/lucene/src/java/org/apache/lucene/index/IndexWriter.java b/lucene/src/java/org/apache/lucene/index/IndexWriter.java index 0f0ba3e85b6..4d924627828 100644 --- a/lucene/src/java/org/apache/lucene/index/IndexWriter.java +++ b/lucene/src/java/org/apache/lucene/index/IndexWriter.java @@ -421,7 +421,7 @@ public class IndexWriter implements Closeable { private final Map readerMap = new HashMap(); /** Forcefully clear changes for the specified segments. This is called on successful merge. */ - synchronized void clear(SegmentInfos infos) throws IOException { + synchronized void clear(List infos) throws IOException { if (infos == null) { for (Map.Entry ent: readerMap.entrySet()) { ent.getValue().hasChanges = false; @@ -511,7 +511,7 @@ public class IndexWriter implements Closeable { return false; } - public synchronized void drop(SegmentInfos infos) throws IOException { + public synchronized void drop(List infos) throws IOException { for(SegmentInfo info : infos) { drop(info); } @@ -2729,7 +2729,7 @@ public class IndexWriter implements Closeable { assert testPoint("startCommitMergeDeletes"); - final SegmentInfos sourceSegments = merge.segments; + final List sourceSegments = merge.segments; if (infoStream != null) message("commitMergeDeletes " + merge.segString(directory)); @@ -2741,7 +2741,7 @@ public class IndexWriter implements Closeable { long minGen = Long.MAX_VALUE; for(int i=0; i < sourceSegments.size(); i++) { - SegmentInfo info = sourceSegments.info(i); + SegmentInfo info = sourceSegments.get(i); minGen = Math.min(info.getBufferedDeletesGen(), minGen); int docCount = info.docCount; final SegmentReader previousReader = merge.readerClones.get(i); @@ -3184,7 +3184,7 @@ public class IndexWriter implements Closeable { // It's possible we are called twice, eg if there was an // exception inside mergeInit if (merge.registerDone) { - final SegmentInfos sourceSegments = merge.segments; + final List sourceSegments = merge.segments; for(SegmentInfo info : sourceSegments) { mergingSegments.remove(info); } @@ -3255,7 +3255,7 @@ public class IndexWriter implements Closeable { int mergedDocCount = 0; - SegmentInfos sourceSegments = merge.segments; + List sourceSegments = merge.segments; SegmentMerger merger = new SegmentMerger(directory, config.getTermIndexInterval(), mergedName, merge, codecs, payloadProcessorProvider, @@ -3276,7 +3276,7 @@ public class IndexWriter implements Closeable { int segUpto = 0; while(segUpto < sourceSegments.size()) { - final SegmentInfo info = sourceSegments.info(segUpto); + final SegmentInfo info = sourceSegments.get(segUpto); // Hold onto the "live" reader; we will use this to // commit merged deletes @@ -3470,14 +3470,14 @@ public class IndexWriter implements Closeable { } /** @lucene.internal */ - public synchronized String segString(SegmentInfos infos) throws IOException { + public synchronized String segString(List infos) throws IOException { StringBuilder buffer = new StringBuilder(); final int count = infos.size(); for(int i = 0; i < count; i++) { if (i > 0) { buffer.append(' '); } - buffer.append(segString(infos.info(i))); + buffer.append(segString(infos.get(i))); } return buffer.toString(); diff --git a/lucene/src/java/org/apache/lucene/index/LogMergePolicy.java b/lucene/src/java/org/apache/lucene/index/LogMergePolicy.java index 1be4f26b77f..fc419bd2f7c 100644 --- a/lucene/src/java/org/apache/lucene/index/LogMergePolicy.java +++ b/lucene/src/java/org/apache/lucene/index/LogMergePolicy.java @@ -20,7 +20,6 @@ package org.apache.lucene.index; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; -import java.util.Comparator; import java.util.List; import java.util.Set; @@ -595,7 +594,7 @@ public abstract class LogMergePolicy extends MergePolicy { } else if (!anyTooLarge) { if (spec == null) spec = new MergeSpecification(); - final SegmentInfos mergeInfos = new SegmentInfos(); + final List mergeInfos = new ArrayList(); for(int i=start;i 0; // Make sure it all adds up: - assert docShift == maxDocID - (newStarts[docMaps.length-1] + merge.segments.info(docMaps.length-1).docCount - delCounts[docMaps.length-1]); + assert docShift == maxDocID - (newStarts[docMaps.length-1] + merge.segments.get(docMaps.length-1).docCount - delCounts[docMaps.length-1]); } public int remap(int oldDocID) { diff --git a/lucene/src/java/org/apache/lucene/index/MergePolicy.java b/lucene/src/java/org/apache/lucene/index/MergePolicy.java index 31289bd18d6..bbced4e9cef 100644 --- a/lucene/src/java/org/apache/lucene/index/MergePolicy.java +++ b/lucene/src/java/org/apache/lucene/index/MergePolicy.java @@ -75,15 +75,21 @@ public abstract class MergePolicy implements java.io.Closeable { long estimatedMergeBytes; // used by IndexWriter List readers; // used by IndexWriter List readerClones; // used by IndexWriter - public final SegmentInfos segments; + public final List segments; + public final int totalDocCount; boolean aborted; Throwable error; boolean paused; - public OneMerge(SegmentInfos segments) { + public OneMerge(List segments) { if (0 == segments.size()) throw new RuntimeException("segments must include at least one segment"); this.segments = segments; + int count = 0; + for(SegmentInfo info : segments) { + count += info.docCount; + } + totalDocCount = count; } /** Record that an exception occurred while executing @@ -147,7 +153,7 @@ public abstract class MergePolicy implements java.io.Closeable { final int numSegments = segments.size(); for(int i=0;i 0) b.append(' '); - b.append(segments.info(i).toString(dir, 0)); + b.append(segments.get(i).toString(dir, 0)); } if (info != null) b.append(" into ").append(info.name); diff --git a/lucene/src/java/org/apache/lucene/index/TieredMergePolicy.java b/lucene/src/java/org/apache/lucene/index/TieredMergePolicy.java index a070ce0f8c4..e69f612553d 100644 --- a/lucene/src/java/org/apache/lucene/index/TieredMergePolicy.java +++ b/lucene/src/java/org/apache/lucene/index/TieredMergePolicy.java @@ -23,6 +23,8 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Comparator; +import java.util.List; +import java.util.ArrayList; /** * Merges segments of approximately equal size, subject to @@ -249,7 +251,7 @@ public class TieredMergePolicy extends MergePolicy { final Collection merging = writer.get().getMergingSegments(); final Collection toBeMerged = new HashSet(); - final SegmentInfos infosSorted = new SegmentInfos(); + final List infosSorted = new ArrayList(); infosSorted.addAll(infos); Collections.sort(infosSorted, segmentByteSizeDescending); @@ -277,7 +279,7 @@ public class TieredMergePolicy extends MergePolicy { // If we have too-large segments, grace them out // of the maxSegmentCount: int tooBigCount = 0; - while (tooBigCount < infosSorted.size() && size(infosSorted.info(tooBigCount)) >= maxMergedSegmentBytes/2.0) { + while (tooBigCount < infosSorted.size() && size(infosSorted.get(tooBigCount)) >= maxMergedSegmentBytes/2.0) { totIndexBytes -= size(infosSorted.get(tooBigCount)); tooBigCount++; } @@ -310,7 +312,7 @@ public class TieredMergePolicy extends MergePolicy { // Gather eligible segments for merging, ie segments // not already being merged and not already picked (by // prior iteration of this loop) for merging: - final SegmentInfos eligible = new SegmentInfos(); + final List eligible = new ArrayList(); for(int idx = tooBigCount; idx best = null; boolean bestTooLarge = false; long bestMergeBytes = 0; @@ -341,10 +343,10 @@ public class TieredMergePolicy extends MergePolicy { long totAfterMergeBytes = 0; - final SegmentInfos candidate = new SegmentInfos(); + final List candidate = new ArrayList(); boolean hitTooLarge = false; for(int idx = startIdx;idx maxMergedSegmentBytes) { @@ -398,7 +400,7 @@ public class TieredMergePolicy extends MergePolicy { } /** Expert: scores one merge; subclasses can override. */ - protected MergeScore score(SegmentInfos candidate, boolean hitTooLarge, long mergingBytes) throws IOException { + protected MergeScore score(List candidate, boolean hitTooLarge, long mergingBytes) throws IOException { long totBeforeMergeBytes = 0; long totAfterMergeBytes = 0; long totAfterMergeBytesFloored = 0; @@ -420,7 +422,7 @@ public class TieredMergePolicy extends MergePolicy { // over time: skew = 1.0/maxMergeAtOnce; } else { - skew = ((double) floorSize(size(candidate.info(0))))/totAfterMergeBytesFloored; + skew = ((double) floorSize(size(candidate.get(0))))/totAfterMergeBytesFloored; } // Strongly favor merges with less skew (smaller @@ -458,7 +460,8 @@ public class TieredMergePolicy extends MergePolicy { if (verbose()) { message("findMergesForOptimize maxSegmentCount=" + maxSegmentCount + " infos=" + writer.get().segString(infos) + " segmentsToOptimize=" + segmentsToOptimize); } - SegmentInfos eligible = new SegmentInfos(); + + List eligible = new ArrayList(); boolean optimizeMergeRunning = false; final Collection merging = writer.get().getMergingSegments(); for(SegmentInfo info : infos) { @@ -499,7 +502,7 @@ public class TieredMergePolicy extends MergePolicy { if (spec == null) { spec = new MergeSpecification(); } - final OneMerge merge = new OneMerge(eligible.range(end-maxMergeAtOnceExplicit, end)); + final OneMerge merge = new OneMerge(eligible.subList(end-maxMergeAtOnceExplicit, end)); if (verbose()) { message("add merge=" + writer.get().segString(merge.segments)); } @@ -510,7 +513,7 @@ public class TieredMergePolicy extends MergePolicy { if (spec == null && !optimizeMergeRunning) { // Do final merge final int numToMerge = end - maxSegmentCount + 1; - final OneMerge merge = new OneMerge(eligible.range(end-numToMerge, end)); + final OneMerge merge = new OneMerge(eligible.subList(end-numToMerge, end)); if (verbose()) { message("add final merge=" + merge.segString(writer.get().getDirectory())); } @@ -527,7 +530,7 @@ public class TieredMergePolicy extends MergePolicy { if (verbose()) { message("findMergesToExpungeDeletes infos=" + writer.get().segString(infos) + " expungeDeletesPctAllowed=" + expungeDeletesPctAllowed); } - final SegmentInfos eligible = new SegmentInfos(); + final List eligible = new ArrayList(); final Collection merging = writer.get().getMergingSegments(); for(SegmentInfo info : infos) { double pctDeletes = 100.*((double) writer.get().numDeletedDocs(info))/info.docCount; @@ -580,7 +583,7 @@ public class TieredMergePolicy extends MergePolicy { spec = new MergeSpecification(); } - final OneMerge merge = new OneMerge(eligible.range(start, upto)); + final OneMerge merge = new OneMerge(eligible.subList(start, upto)); if (verbose()) { message("add merge=" + writer.get().segString(merge.segments)); } diff --git a/lucene/src/java/org/apache/lucene/index/UpgradeIndexMergePolicy.java b/lucene/src/java/org/apache/lucene/index/UpgradeIndexMergePolicy.java index cfc42aaae11..7e57888461d 100644 --- a/lucene/src/java/org/apache/lucene/index/UpgradeIndexMergePolicy.java +++ b/lucene/src/java/org/apache/lucene/index/UpgradeIndexMergePolicy.java @@ -20,7 +20,9 @@ package org.apache.lucene.index; import org.apache.lucene.util.Constants; import java.io.IOException; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; /** This {@link MergePolicy} is used for upgrading all existing segments of @@ -101,7 +103,7 @@ public class UpgradeIndexMergePolicy extends MergePolicy { if (verbose()) message("findMergesForOptimize: " + base.getClass().getSimpleName() + " does not want to merge all old segments, merge remaining ones into new segment: " + oldSegments); - final SegmentInfos newInfos = new SegmentInfos(); + final List newInfos = new ArrayList(); for (final SegmentInfo si : segmentInfos) { if (oldSegments.contains(si)) { newInfos.add(si); diff --git a/lucene/src/test-framework/org/apache/lucene/index/MockRandomMergePolicy.java b/lucene/src/test-framework/org/apache/lucene/index/MockRandomMergePolicy.java index f2ee32950c8..0cc621aff6d 100644 --- a/lucene/src/test-framework/org/apache/lucene/index/MockRandomMergePolicy.java +++ b/lucene/src/test-framework/org/apache/lucene/index/MockRandomMergePolicy.java @@ -18,7 +18,9 @@ package org.apache.lucene.index; */ import java.io.IOException; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Random; import java.util.Set; @@ -58,7 +60,7 @@ public class MockRandomMergePolicy extends MergePolicy { SegmentInfos segmentInfos, int maxSegmentCount, Set segmentsToOptimize) throws CorruptIndexException, IOException { - final SegmentInfos eligibleSegments = new SegmentInfos(); + final List eligibleSegments = new ArrayList(); for(SegmentInfo info : segmentInfos) { if (segmentsToOptimize.contains(info)) { eligibleSegments.add(info); @@ -76,7 +78,7 @@ public class MockRandomMergePolicy extends MergePolicy { while(upto < eligibleSegments.size()) { int max = Math.min(10, eligibleSegments.size()-upto); int inc = max <= 2 ? max : _TestUtil.nextInt(random, 2, max); - mergeSpec.add(new OneMerge(eligibleSegments.range(upto, upto+inc))); + mergeSpec.add(new OneMerge(eligibleSegments.subList(upto, upto+inc))); upto += inc; } } From e4f9bfdd06873f2bfc948525d44307d88e1f9f27 Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Tue, 10 May 2011 18:29:35 +0000 Subject: [PATCH 49/57] LUCENE-3084, LUCENE-1076: update trunk CHANGES git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1101584 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/CHANGES.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 3ffad76a32f..6d14eccd3bd 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -472,6 +472,14 @@ Changes in backwards compatibility policy a method getHeapArray() was added to retrieve the internal heap array as a non-generic Object[]. (Uwe Schindler, Yonik Seeley) +* LUCENE-1076: IndexWriter.setInfoStream now throws IOException + (Mike McCandless, Shai Erera) + +* LUCENE-3084: MergePolicy.OneMerge.segments was changed from + SegmentInfos to a List; this is actually a minor change + because SegmentInfos itself extends Vector. (Uwe + Schindler, Mike McCandless) + Changes in runtime behavior * LUCENE-3065: When a NumericField is retrieved from a Document loaded From 02bc22d21a303f9324822e39008a3be06e78534b Mon Sep 17 00:00:00 2001 From: Yonik Seeley Date: Wed, 11 May 2011 20:02:54 +0000 Subject: [PATCH 50/57] SOLR-2496: add array-of-object JSON format and commitWithin, overwrite request params git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1102058 13f79535-47bb-0310-9956-ffa450edef68 --- solr/CHANGES.txt | 6 + solr/example/exampledocs/books.json | 15 +- .../org/apache/solr/handler/JsonLoader.java | 219 +++++++++++------- .../handler/JsonUpdateRequestHandler.java | 2 +- .../apache/solr/handler/JsonLoaderTest.java | 71 +++++- 5 files changed, 207 insertions(+), 106 deletions(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 877183cba80..42555a66b8a 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -270,6 +270,12 @@ Detailed Change List New Features ---------------------- +* SOLR-2496: Add ability to specify overwrite and commitWithin as request + parameters (e.g. specified in the URL) when using the JSON update format, + and added a simplified format for specifying multiple documents. + Example: [{"id":"doc1"},{"id":"doc2"}] + (yonik) + Optimizations ---------------------- diff --git a/solr/example/exampledocs/books.json b/solr/example/exampledocs/books.json index f805c076558..188e0734fbe 100644 --- a/solr/example/exampledocs/books.json +++ b/solr/example/exampledocs/books.json @@ -1,7 +1,5 @@ -{ - -"add": { - "doc": { +[ + { "id" : "978-0641723445", "cat" : ["book","hardcover"], "title" : "The Lightning Thief", @@ -13,11 +11,8 @@ "price" : 12.50, "pages_i" : 384 } -} - , -"add": { - "doc": { + { "id" : "978-1423103349", "cat" : ["book","paperback"], "title" : "The Sea of Monsters", @@ -29,6 +24,4 @@ "price" : 6.49, "pages_i" : 304 } -} - -} +] diff --git a/solr/src/java/org/apache/solr/handler/JsonLoader.java b/solr/src/java/org/apache/solr/handler/JsonLoader.java index c233ce634e4..34118a07402 100644 --- a/solr/src/java/org/apache/solr/handler/JsonLoader.java +++ b/solr/src/java/org/apache/solr/handler/JsonLoader.java @@ -23,6 +23,7 @@ import java.util.Stack; import org.apache.commons.io.IOUtils; import org.apache.noggit.JSONParser; +import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.SolrInputField; import org.apache.solr.common.util.ContentStream; @@ -43,10 +44,18 @@ import org.slf4j.LoggerFactory; class JsonLoader extends ContentStreamLoader { final static Logger log = LoggerFactory.getLogger( JsonLoader.class ); - protected UpdateRequestProcessor processor; + protected final UpdateRequestProcessor processor; + protected final SolrQueryRequest req; + protected JSONParser parser; + protected final int commitWithin; + protected final boolean overwrite; - public JsonLoader(UpdateRequestProcessor processor) { + public JsonLoader(SolrQueryRequest req, UpdateRequestProcessor processor) { this.processor = processor; + this.req = req; + + commitWithin = req.getParams().getInt(XmlUpdateRequestHandler.COMMIT_WITHIN, -1); + overwrite = req.getParams().getBool(XmlUpdateRequestHandler.OVERWRITE, true); } @Override @@ -55,14 +64,14 @@ class JsonLoader extends ContentStreamLoader { Reader reader = null; try { reader = stream.getReader(); - if (XmlUpdateRequestHandler.log.isTraceEnabled()) { + if (log.isTraceEnabled()) { String body = IOUtils.toString(reader); - XmlUpdateRequestHandler.log.trace("body", body); + log.trace("body", body); reader = new StringReader(body); } - JSONParser parser = new JSONParser(reader); - this.processUpdate(req, processor, parser); + parser = new JSONParser(reader); + this.processUpdate(); } finally { IOUtils.closeQuietly(reader); @@ -70,39 +79,50 @@ class JsonLoader extends ContentStreamLoader { } @SuppressWarnings("fallthrough") - void processUpdate(SolrQueryRequest req, UpdateRequestProcessor processor, JSONParser parser) throws IOException + void processUpdate() throws IOException { int ev = parser.nextEvent(); while( ev != JSONParser.EOF ) { switch( ev ) { + case JSONParser.ARRAY_START: + handleAdds(); + break; + case JSONParser.STRING: if( parser.wasKey() ) { String v = parser.getString(); if( v.equals( XmlUpdateRequestHandler.ADD ) ) { - processor.processAdd( parseAdd(req, parser ) ); + int ev2 = parser.nextEvent(); + if (ev2 == JSONParser.OBJECT_START) { + processor.processAdd( parseAdd() ); + } else if (ev2 == JSONParser.ARRAY_START) { + handleAdds(); + } else { + assertEvent(ev2, JSONParser.OBJECT_START); + } } else if( v.equals( XmlUpdateRequestHandler.COMMIT ) ) { CommitUpdateCommand cmd = new CommitUpdateCommand(req, false ); cmd.waitFlush = cmd.waitSearcher = true; - parseCommitOptions( parser, cmd ); + parseCommitOptions( cmd ); processor.processCommit( cmd ); } else if( v.equals( XmlUpdateRequestHandler.OPTIMIZE ) ) { CommitUpdateCommand cmd = new CommitUpdateCommand(req, true ); cmd.waitFlush = cmd.waitSearcher = true; - parseCommitOptions( parser, cmd ); + parseCommitOptions( cmd ); processor.processCommit( cmd ); } else if( v.equals( XmlUpdateRequestHandler.DELETE ) ) { - processor.processDelete( parseDelete(req, parser ) ); + processor.processDelete( parseDelete() ); } else if( v.equals( XmlUpdateRequestHandler.ROLLBACK ) ) { - processor.processRollback( parseRollback(req, parser ) ); + processor.processRollback( parseRollback() ); } else { - throw new IOException( "Unknown command: "+v+" ["+parser.getPosition()+"]" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unknown command: "+v+" ["+parser.getPosition()+"]" ); } break; } @@ -117,12 +137,11 @@ class JsonLoader extends ContentStreamLoader { case JSONParser.OBJECT_START: case JSONParser.OBJECT_END: - case JSONParser.ARRAY_START: case JSONParser.ARRAY_END: break; default: - System.out.println("UNKNOWN_EVENT_ID:"+ev); + log.info("Noggit UNKNOWN_EVENT_ID:"+ev); break; } // read the next event @@ -130,187 +149,211 @@ class JsonLoader extends ContentStreamLoader { } } - DeleteUpdateCommand parseDelete(SolrQueryRequest req, JSONParser js) throws IOException { - assertNextEvent( js, JSONParser.OBJECT_START ); + DeleteUpdateCommand parseDelete() throws IOException { + assertNextEvent( JSONParser.OBJECT_START ); DeleteUpdateCommand cmd = new DeleteUpdateCommand(req); - + while( true ) { - int ev = js.nextEvent(); + int ev = parser.nextEvent(); if( ev == JSONParser.STRING ) { - String key = js.getString(); - if( js.wasKey() ) { + String key = parser.getString(); + if( parser.wasKey() ) { if( "id".equals( key ) ) { - cmd.id = js.getString(); + cmd.id = parser.getString(); } else if( "query".equals(key) ) { - cmd.query = js.getString(); + cmd.query = parser.getString(); } else { - throw new IOException( "Unknown key: "+key+" ["+js.getPosition()+"]" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unknown key: "+key+" ["+parser.getPosition()+"]" ); } } else { - throw new IOException( + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "invalid string: " + key - +" at ["+js.getPosition()+"]" ); + +" at ["+parser.getPosition()+"]" ); } } else if( ev == JSONParser.OBJECT_END ) { if( cmd.id == null && cmd.query == null ) { - throw new IOException( "Missing id or query for delete ["+js.getPosition()+"]" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Missing id or query for delete ["+parser.getPosition()+"]" ); } return cmd; } else { - throw new IOException( + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Got: "+JSONParser.getEventString( ev ) - +" at ["+js.getPosition()+"]" ); + +" at ["+parser.getPosition()+"]" ); } } } - RollbackUpdateCommand parseRollback(SolrQueryRequest req, JSONParser js) throws IOException { - assertNextEvent( js, JSONParser.OBJECT_START ); - assertNextEvent( js, JSONParser.OBJECT_END ); + RollbackUpdateCommand parseRollback() throws IOException { + assertNextEvent( JSONParser.OBJECT_START ); + assertNextEvent( JSONParser.OBJECT_END ); return new RollbackUpdateCommand(req); } - void parseCommitOptions( JSONParser js, CommitUpdateCommand cmd ) throws IOException + void parseCommitOptions(CommitUpdateCommand cmd ) throws IOException { - assertNextEvent( js, JSONParser.OBJECT_START ); + assertNextEvent( JSONParser.OBJECT_START ); while( true ) { - int ev = js.nextEvent(); + int ev = parser.nextEvent(); if( ev == JSONParser.STRING ) { - String key = js.getString(); - if( js.wasKey() ) { + String key = parser.getString(); + if( parser.wasKey() ) { if( XmlUpdateRequestHandler.WAIT_SEARCHER.equals( key ) ) { - cmd.waitSearcher = js.getBoolean(); + cmd.waitSearcher = parser.getBoolean(); } else if( XmlUpdateRequestHandler.WAIT_FLUSH.equals( key ) ) { - cmd.waitFlush = js.getBoolean(); + cmd.waitFlush = parser.getBoolean(); } else { - throw new IOException( "Unknown key: "+key+" ["+js.getPosition()+"]" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unknown key: "+key+" ["+parser.getPosition()+"]" ); } } else { - throw new IOException( + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "invalid string: " + key - +" at ["+js.getPosition()+"]" ); + +" at ["+parser.getPosition()+"]" ); } } else if( ev == JSONParser.OBJECT_END ) { return; } else { - throw new IOException( + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Got: "+JSONParser.getEventString( ev ) - +" at ["+js.getPosition()+"]" ); + +" at ["+parser.getPosition()+"]" ); } } } - AddUpdateCommand parseAdd(SolrQueryRequest req, JSONParser js ) throws IOException + AddUpdateCommand parseAdd() throws IOException { - assertNextEvent( js, JSONParser.OBJECT_START ); AddUpdateCommand cmd = new AddUpdateCommand(req); + cmd.commitWithin = commitWithin; + cmd.overwrite = overwrite; + float boost = 1.0f; while( true ) { - int ev = js.nextEvent(); + int ev = parser.nextEvent(); if( ev == JSONParser.STRING ) { - if( js.wasKey() ) { - String key = js.getString(); + if( parser.wasKey() ) { + String key = parser.getString(); if( "doc".equals( key ) ) { if( cmd.solrDoc != null ) { - throw new IOException( "multiple docs in same add command" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "multiple docs in same add command" ); } - ev = assertNextEvent( js, JSONParser.OBJECT_START ); - cmd.solrDoc = parseDoc( ev, js ); + ev = assertNextEvent( JSONParser.OBJECT_START ); + cmd.solrDoc = parseDoc( ev ); } else if( XmlUpdateRequestHandler.OVERWRITE.equals( key ) ) { - cmd.overwrite = js.getBoolean(); // reads next boolean + cmd.overwrite = parser.getBoolean(); // reads next boolean } else if( XmlUpdateRequestHandler.COMMIT_WITHIN.equals( key ) ) { - cmd.commitWithin = (int)js.getLong(); + cmd.commitWithin = (int)parser.getLong(); } else if( "boost".equals( key ) ) { - boost = Float.parseFloat( js.getNumberChars().toString() ); + boost = Float.parseFloat( parser.getNumberChars().toString() ); } else { - throw new IOException( "Unknown key: "+key+" ["+js.getPosition()+"]" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unknown key: "+key+" ["+parser.getPosition()+"]" ); } } else { - throw new IOException( + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Should be a key " - +" at ["+js.getPosition()+"]" ); + +" at ["+parser.getPosition()+"]" ); } } else if( ev == JSONParser.OBJECT_END ) { if( cmd.solrDoc == null ) { - throw new IOException("missing solr document. "+js.getPosition() ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,"missing solr document. "+parser.getPosition() ); } cmd.solrDoc.setDocumentBoost( boost ); return cmd; } else { - throw new IOException( + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Got: "+JSONParser.getEventString( ev ) - +" at ["+js.getPosition()+"]" ); + +" at ["+parser.getPosition()+"]" ); } } } - - int assertNextEvent( JSONParser parser, int ev ) throws IOException + + + void handleAdds() throws IOException + { + while( true ) { + AddUpdateCommand cmd = new AddUpdateCommand(req); + cmd.commitWithin = commitWithin; + cmd.overwrite = overwrite; + + int ev = parser.nextEvent(); + if (ev == JSONParser.ARRAY_END) break; + + assertEvent(ev, JSONParser.OBJECT_START); + cmd.solrDoc = parseDoc(ev); + processor.processAdd(cmd); + } + } + + + int assertNextEvent(int expected ) throws IOException { int got = parser.nextEvent(); - if( ev != got ) { - throw new IOException( - "Expected: "+JSONParser.getEventString( ev ) - +" but got "+JSONParser.getEventString( got ) - +" at ["+parser.getPosition()+"]" ); - } + assertEvent(got, expected); return got; } + + void assertEvent(int ev, int expected) { + if( ev != expected ) { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, + "Expected: "+JSONParser.getEventString( expected ) + +" but got "+JSONParser.getEventString( ev ) + +" at ["+parser.getPosition()+"]" ); + } + } - SolrInputDocument parseDoc( int ev, JSONParser js ) throws IOException + SolrInputDocument parseDoc(int ev) throws IOException { Stack stack = new Stack(); Object obj = null; boolean inArray = false; if( ev != JSONParser.OBJECT_START ) { - throw new IOException( "object should already be started" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "object should already be started" ); } while( true ) { - //System.out.println( ev + "["+JSONParser.getEventString(ev)+"] "+js.wasKey() ); //+ js.getString() ); + //System.out.println( ev + "["+JSONParser.getEventString(ev)+"] "+parser.wasKey() ); //+ parser.getString() ); switch (ev) { case JSONParser.STRING: - if( js.wasKey() ) { + if( parser.wasKey() ) { obj = stack.peek(); - String v = js.getString(); + String v = parser.getString(); if( obj instanceof SolrInputField ) { SolrInputField field = (SolrInputField)obj; if( "boost".equals( v ) ) { - ev = js.nextEvent(); + ev = parser.nextEvent(); if( ev != JSONParser.NUMBER && ev != JSONParser.LONG && ev != JSONParser.BIGNUMBER ) { - throw new IOException( "boost should have number! "+JSONParser.getEventString(ev) ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "boost should have number! "+JSONParser.getEventString(ev) ); } - field.setBoost( Float.valueOf( js.getNumberChars().toString() ) ); + field.setBoost( Float.valueOf( parser.getNumberChars().toString() ) ); } else if( "value".equals( v ) ) { // nothing special... stack.push( field ); // so it can be popped } else { - throw new IOException( "invalid key: "+v + " ["+js.getPosition()+"]" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "invalid key: "+v + " ["+ parser.getPosition()+"]" ); } } else if( obj instanceof SolrInputDocument ) { @@ -323,22 +366,22 @@ class JsonLoader extends ContentStreamLoader { stack.push( f ); } else { - throw new IOException( "hymmm ["+js.getPosition()+"]" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "hymmm ["+ parser.getPosition()+"]" ); } } else { - addValToField(stack, js.getString(), inArray, js); + addValToField(stack, parser.getString(), inArray, parser); } break; case JSONParser.LONG: case JSONParser.NUMBER: case JSONParser.BIGNUMBER: - addValToField(stack, js.getNumberChars().toString(), inArray, js); + addValToField(stack, parser.getNumberChars().toString(), inArray, parser); break; case JSONParser.BOOLEAN: - addValToField(stack, js.getBoolean(),inArray, js); + addValToField(stack, parser.getBoolean(),inArray, parser); break; case JSONParser.OBJECT_START: @@ -351,7 +394,7 @@ class JsonLoader extends ContentStreamLoader { // should alreay be pushed... } else { - throw new IOException( "should not start new object with: "+obj + " ["+js.getPosition()+"]" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "should not start new object with: "+obj + " ["+ parser.getPosition()+"]" ); } } break; @@ -365,7 +408,7 @@ class JsonLoader extends ContentStreamLoader { // should already be pushed... } else { - throw new IOException( "should not start new object with: "+obj + " ["+js.getPosition()+"]" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "should not start new object with: "+obj + " ["+ parser.getPosition()+"]" ); } break; @@ -383,18 +426,18 @@ class JsonLoader extends ContentStreamLoader { break; } - ev = js.nextEvent(); + ev = parser.nextEvent(); if( ev == JSONParser.EOF ) { - throw new IOException( "should finish doc first!" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "should finish doc first!" ); } } } - static void addValToField( Stack stack, Object val, boolean inArray, JSONParser js ) throws IOException + static void addValToField( Stack stack, Object val, boolean inArray, JSONParser parser ) throws IOException { Object obj = stack.peek(); if( !(obj instanceof SolrInputField) ) { - throw new IOException( "hymmm ["+js.getPosition()+"]" ); + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "hymmm ["+parser.getPosition()+"]" ); } SolrInputField f = inArray diff --git a/solr/src/java/org/apache/solr/handler/JsonUpdateRequestHandler.java b/solr/src/java/org/apache/solr/handler/JsonUpdateRequestHandler.java index 9f36c37d785..213089d0943 100644 --- a/solr/src/java/org/apache/solr/handler/JsonUpdateRequestHandler.java +++ b/solr/src/java/org/apache/solr/handler/JsonUpdateRequestHandler.java @@ -37,7 +37,7 @@ public class JsonUpdateRequestHandler extends ContentStreamHandlerBase { @Override protected ContentStreamLoader newLoader(SolrQueryRequest req, UpdateRequestProcessor processor) { - return new JsonLoader(processor); + return new JsonLoader(req, processor); } //////////////////////// SolrInfoMBeans methods ////////////////////// diff --git a/solr/src/test/org/apache/solr/handler/JsonLoaderTest.java b/solr/src/test/org/apache/solr/handler/JsonLoaderTest.java index e6635475356..5deec94f01b 100644 --- a/solr/src/test/org/apache/solr/handler/JsonLoaderTest.java +++ b/solr/src/test/org/apache/solr/handler/JsonLoaderTest.java @@ -26,7 +26,9 @@ import org.apache.lucene.util.LuceneTestCase; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.SolrInputField; +import org.apache.solr.common.util.ContentStreamBase; import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.update.AddUpdateCommand; import org.apache.solr.update.CommitUpdateCommand; import org.apache.solr.update.DeleteUpdateCommand; @@ -81,13 +83,11 @@ public class JsonLoaderTest extends SolrTestCaseJ4 { public void testParsing() throws Exception { SolrQueryRequest req = req(); - Reader reader = new StringReader(input); - + SolrQueryResponse rsp = new SolrQueryResponse(); BufferingRequestProcessor p = new BufferingRequestProcessor(null); - JsonLoader loader = new JsonLoader( p ); - - loader.processUpdate(req, p, new JSONParser(reader) ); - + JsonLoader loader = new JsonLoader( req, p ); + loader.load(req, rsp, new ContentStreamBase.StringStream(input)); + assertEquals( 2, p.addCommands.size() ); AddUpdateCommand add = p.addCommands.get(0); @@ -133,8 +133,67 @@ public class JsonLoaderTest extends SolrTestCaseJ4 { req.close(); } + + + public void testSimpleFormat() throws Exception + { + String str = "[{'id':'1'},{'id':'2'}]".replace('\'', '"'); + SolrQueryRequest req = req("commitWithin","100", "overwrite","false"); + SolrQueryResponse rsp = new SolrQueryResponse(); + BufferingRequestProcessor p = new BufferingRequestProcessor(null); + JsonLoader loader = new JsonLoader( req, p ); + loader.load(req, rsp, new ContentStreamBase.StringStream(str)); + + assertEquals( 2, p.addCommands.size() ); + + AddUpdateCommand add = p.addCommands.get(0); + SolrInputDocument d = add.solrDoc; + SolrInputField f = d.getField( "id" ); + assertEquals("1", f.getValue()); + assertEquals(add.commitWithin, 100); + assertEquals(add.overwrite, false); + + add = p.addCommands.get(1); + d = add.solrDoc; + f = d.getField( "id" ); + assertEquals("2", f.getValue()); + assertEquals(add.commitWithin, 100); + assertEquals(add.overwrite, false); + + req.close(); + } + + public void testSimpleFormatInAdd() throws Exception + { + String str = "{'add':[{'id':'1'},{'id':'2'}]}".replace('\'', '"'); + SolrQueryRequest req = req(); + SolrQueryResponse rsp = new SolrQueryResponse(); + BufferingRequestProcessor p = new BufferingRequestProcessor(null); + JsonLoader loader = new JsonLoader( req, p ); + loader.load(req, rsp, new ContentStreamBase.StringStream(str)); + + assertEquals( 2, p.addCommands.size() ); + + AddUpdateCommand add = p.addCommands.get(0); + SolrInputDocument d = add.solrDoc; + SolrInputField f = d.getField( "id" ); + assertEquals("1", f.getValue()); + assertEquals(add.commitWithin, -1); + assertEquals(add.overwrite, true); + + add = p.addCommands.get(1); + d = add.solrDoc; + f = d.getField( "id" ); + assertEquals("2", f.getValue()); + assertEquals(add.commitWithin, -1); + assertEquals(add.overwrite, true); + + req.close(); + } + } + class BufferingRequestProcessor extends UpdateRequestProcessor { List addCommands = new ArrayList(); From b3bb2aa0ac571169d369b53bd8f009d918903b75 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Wed, 11 May 2011 22:37:16 +0000 Subject: [PATCH 51/57] fix 3.x section of CHANGES.txt to be accurate git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1102119 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/CHANGES.txt | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 6d14eccd3bd..bbd2579bd41 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -498,19 +498,37 @@ New features that allows to upgrade all segments to last recent supported index format without fully optimizing. (Uwe Schindler, Mike McCandless) -Optimizations +* LUCENE-1076: Added TieredMergePolicy which is able to merge non-contiguous + segments, which means docIDs no longer necessarily stay "in order". + (Mike McCandless, Shai Erera) -* LUCENE-2990: ArrayUtil/CollectionUtil.*Sort() methods now exit early - on empty or one-element lists/arrays. (Uwe Schindler) +* LUCENE-3071: Adding ReversePathHierarchyTokenizer, added skip parameter to + PathHierarchyTokenizer (Olivier Favre via ryan) API Changes +* LUCENE-3061: IndexWriter's getNextMerge() and merge(OneMerge) are now public + (though @lucene.experimental), allowing for custom MergeScheduler + implementations. (Shai Erera) + * LUCENE-3065: Document.getField() was deprecated, as it throws ClassCastException when loading lazy fields or NumericFields. (Uwe Schindler, Ryan McKinley, Mike McCandless) +Optimizations + +* LUCENE-2990: ArrayUtil/CollectionUtil.*Sort() methods now exit early + on empty or one-element lists/arrays. (Uwe Schindler) + +* LUCENE-2897: Apply deleted terms while flushing a segment. We still + buffer deleted terms to later apply to past segments. (Mike McCandless) + Bug fixes +* LUCENE-2996: addIndexes(IndexReader) did not flush before adding the new + indexes, causing existing deletions to be applied on the incoming indexes as + well. (Shai Erera, Mike McCandless) + * LUCENE-3024: Index with more than 2.1B terms was hitting AIOOBE when seeking TermEnum (eg used by Solr's faceting) (Tom Burton-West, Mike McCandless) @@ -528,6 +546,12 @@ Bug fixes PhraseQuery as term with lower doc freq will also have less positions. (Uwe Schindler, Robert Muir, Otis Gospodnetic) +Test Cases + +* LUCENE-3002: added 'tests.iter.min' to control 'tests.iter' by allowing to + stop iterating if at least 'tests.iter.min' ran and a failure occured. + (Shai Erera, Chris Hostetter) + ======================= Lucene 3.1.0 ======================= Changes in backwards compatibility policy From a871b29ed6e6ae060c2e3da2cbd6d3fdd9ac61ea Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Wed, 11 May 2011 22:43:54 +0000 Subject: [PATCH 52/57] LUCENE-3086: add ElisionFilter to ItalianAnalyzer git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1102120 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/contrib/CHANGES.txt | 5 +++++ .../lucene/analysis/fr/ElisionFilter.java | 2 -- .../lucene/analysis/it/ItalianAnalyzer.java | 22 ++++++++++++++++++- .../analysis/it/TestItalianAnalyzer.java | 15 +++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/lucene/contrib/CHANGES.txt b/lucene/contrib/CHANGES.txt index 46a60c87712..2e6021bf090 100644 --- a/lucene/contrib/CHANGES.txt +++ b/lucene/contrib/CHANGES.txt @@ -50,6 +50,11 @@ Bug Fixes ======================= Lucene 3.x (not yet released) ======================= +Changes in runtime behavior + + * LUCENE-3086: ItalianAnalyzer now uses ElisionFilter with a set of Italian + contractions by default. (Robert Muir) + Bug Fixes * LUCENE-3045: fixed QueryNodeImpl.containsTag(String key) that was diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/fr/ElisionFilter.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/fr/ElisionFilter.java index b43a5c3b0dc..507a114336a 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/fr/ElisionFilter.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/fr/ElisionFilter.java @@ -31,8 +31,6 @@ import org.apache.lucene.util.Version; /** * Removes elisions from a {@link TokenStream}. For example, "l'avion" (the plane) will be * tokenized as "avion" (plane). - *

    - * Note that {@link StandardTokenizer} sees " ' " as a space, and cuts it out. * * @see Elision in Wikipedia */ diff --git a/modules/analysis/common/src/java/org/apache/lucene/analysis/it/ItalianAnalyzer.java b/modules/analysis/common/src/java/org/apache/lucene/analysis/it/ItalianAnalyzer.java index adb51f29d44..bd8cc47a40f 100644 --- a/modules/analysis/common/src/java/org/apache/lucene/analysis/it/ItalianAnalyzer.java +++ b/modules/analysis/common/src/java/org/apache/lucene/analysis/it/ItalianAnalyzer.java @@ -19,11 +19,13 @@ package org.apache.lucene.analysis.it; import java.io.IOException; import java.io.Reader; +import java.util.Arrays; import java.util.Set; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.core.LowerCaseFilter; import org.apache.lucene.analysis.core.StopFilter; +import org.apache.lucene.analysis.fr.ElisionFilter; import org.apache.lucene.analysis.miscellaneous.KeywordMarkerFilter; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.Tokenizer; @@ -38,6 +40,14 @@ import org.tartarus.snowball.ext.ItalianStemmer; /** * {@link Analyzer} for Italian. + *

    + * + *

    You must specify the required {@link Version} + * compatibility when creating ItalianAnalyzer: + *

    */ public final class ItalianAnalyzer extends StopwordAnalyzerBase { private final Set stemExclusionSet; @@ -45,6 +55,13 @@ public final class ItalianAnalyzer extends StopwordAnalyzerBase { /** File containing default Italian stopwords. */ public final static String DEFAULT_STOPWORD_FILE = "italian_stop.txt"; + private static final CharArraySet DEFAULT_ARTICLES = CharArraySet.unmodifiableSet( + new CharArraySet(Version.LUCENE_CURRENT, + Arrays.asList( + "c", "l", "all", "dall", "dell", "nell", "sull", "coll", "pell", + "gl", "agl", "dagl", "degl", "negl", "sugl", "un", "m", "t", "s", "v", "d" + ), true)); + /** * Returns an unmodifiable instance of the default stop words set. * @return default stop words set. @@ -112,7 +129,7 @@ public final class ItalianAnalyzer extends StopwordAnalyzerBase { * @return A * {@link org.apache.lucene.analysis.util.ReusableAnalyzerBase.TokenStreamComponents} * built from an {@link StandardTokenizer} filtered with - * {@link StandardFilter}, {@link LowerCaseFilter}, {@link StopFilter} + * {@link StandardFilter}, {@link ElisionFilter}, {@link LowerCaseFilter}, {@link StopFilter} * , {@link KeywordMarkerFilter} if a stem exclusion set is * provided and {@link SnowballFilter}. */ @@ -121,6 +138,9 @@ public final class ItalianAnalyzer extends StopwordAnalyzerBase { Reader reader) { final Tokenizer source = new StandardTokenizer(matchVersion, reader); TokenStream result = new StandardFilter(matchVersion, source); + if (matchVersion.onOrAfter(Version.LUCENE_32)) { + result = new ElisionFilter(matchVersion, result, DEFAULT_ARTICLES); + } result = new LowerCaseFilter(matchVersion, result); result = new StopFilter(matchVersion, result, stopwords); if(!stemExclusionSet.isEmpty()) diff --git a/modules/analysis/common/src/test/org/apache/lucene/analysis/it/TestItalianAnalyzer.java b/modules/analysis/common/src/test/org/apache/lucene/analysis/it/TestItalianAnalyzer.java index ae4bf2f2d24..83d7a863b35 100644 --- a/modules/analysis/common/src/test/org/apache/lucene/analysis/it/TestItalianAnalyzer.java +++ b/modules/analysis/common/src/test/org/apache/lucene/analysis/it/TestItalianAnalyzer.java @@ -23,6 +23,7 @@ import java.util.Set; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.BaseTokenStreamTestCase; +import org.apache.lucene.util.Version; public class TestItalianAnalyzer extends BaseTokenStreamTestCase { /** This test fails with NPE when the @@ -55,4 +56,18 @@ public class TestItalianAnalyzer extends BaseTokenStreamTestCase { public void testRandomStrings() throws Exception { checkRandomData(random, new ItalianAnalyzer(TEST_VERSION_CURRENT), 10000*RANDOM_MULTIPLIER); } + + /** test that the elisionfilter is working */ + public void testContractions() throws IOException { + Analyzer a = new ItalianAnalyzer(TEST_VERSION_CURRENT); + assertAnalyzesTo(a, "dell'Italia", new String[] { "ital" }); + assertAnalyzesTo(a, "l'Italiano", new String[] { "ital" }); + } + + /** test that we don't enable this before 3.2*/ + public void testContractionsBackwards() throws IOException { + Analyzer a = new ItalianAnalyzer(Version.LUCENE_31); + assertAnalyzesTo(a, "dell'Italia", new String[] { "dell'ital" }); + assertAnalyzesTo(a, "l'Italiano", new String[] { "l'ital" }); + } } From 6ef7db2eaa387ff1f2954b3ad6a7a5746ce8a9fd Mon Sep 17 00:00:00 2001 From: Dawid Weiss Date: Thu, 12 May 2011 08:41:10 +0000 Subject: [PATCH 53/57] Reversing in place rewritten slightly. Seems more intuitive to me now. git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1102205 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/lucene/util/automaton/fst/FST.java | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/util/automaton/fst/FST.java b/lucene/src/java/org/apache/lucene/util/automaton/fst/FST.java index dde66270873..512d07f28d7 100644 --- a/lucene/src/java/org/apache/lucene/util/automaton/fst/FST.java +++ b/lucene/src/java/org/apache/lucene/util/automaton/fst/FST.java @@ -446,25 +446,17 @@ public class FST { // reverse bytes in-place; we do this so that the // "BIT_TARGET_NEXT" opto can work, ie, it reads the // node just before the current one - final int endAddress = writer.posWrite; - final int stopAt = (endAddress - startAddress)/2; - int upto = 0; - while (upto < stopAt) { - final byte b = bytes[startAddress+upto]; - bytes[startAddress+upto] = bytes[endAddress-upto-1]; - bytes[endAddress-upto-1] = b; - upto++; + final int endAddress = lastFrozenNode = writer.posWrite - 1; + + int left = startAddress; + int right = endAddress; + while (left < right) { + final byte b = bytes[left]; + bytes[left++] = bytes[right]; + bytes[right--] = b; } - lastFrozenNode = endAddress - 1; - /* - System.out.println(" return node addr=" + (endAddress-1)); - for(int i=endAddress-1;i>=startAddress;i--) { - System.out.println(" bytes[" + i + "]=" + bytes[i]); - } - */ - - return endAddress-1; + return endAddress; } /** Fills virtual 'start' arc, ie, an empty incoming arc to From 858aa929c4b039325f0881261406f29c40306da4 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Thu, 12 May 2011 13:32:32 +0000 Subject: [PATCH 54/57] LUCENE-3064: add checks to MockTokenizer to enforce proper consumption git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1102290 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/search/highlight/Highlighter.java | 1 + .../search/highlight/HighlighterTest.java | 20 +++++-- .../highlight/OffsetLimitTokenFilterTest.java | 14 +++-- .../lucene/search/FuzzyLikeThisQuery.java | 5 +- .../lucene/search/similar/MoreLikeThis.java | 4 +- .../analyzing/AnalyzingQueryParser.java | 19 ++++++- .../AnalyzerQueryNodeProcessor.java | 5 ++ .../org/apache/lucene/wordnet/SynExpand.java | 4 +- .../wordnet/TestSynonymTokenFilter.java | 1 - .../builders/LikeThisQueryBuilder.java | 3 ++ .../builders/SpanOrTermsBuilder.java | 3 ++ .../builders/TermsFilterBuilder.java | 3 ++ .../xmlparser/builders/TermsQueryBuilder.java | 3 ++ .../lucene/queryParser/QueryParserBase.java | 1 + .../analysis/BaseTokenStreamTestCase.java | 1 + .../apache/lucene/analysis/MockAnalyzer.java | 12 ++++- .../lucene/analysis/MockPayloadAnalyzer.java | 1 + .../apache/lucene/analysis/MockTokenizer.java | 52 +++++++++++++++++++ .../lucene/analysis/TestMockAnalyzer.java | 1 + .../index/TestIndexWriterExceptions.java | 24 ++++++--- .../apache/lucene/index/TestLongPostings.java | 1 + .../lucene/index/TestTermVectorsWriter.java | 4 +- .../apache/lucene/search/TestPhraseQuery.java | 3 ++ 23 files changed, 164 insertions(+), 21 deletions(-) diff --git a/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/Highlighter.java b/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/Highlighter.java index 2c2104570e4..3957c46f3df 100644 --- a/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/Highlighter.java +++ b/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/Highlighter.java @@ -355,6 +355,7 @@ public class Highlighter { try { + tokenStream.end(); tokenStream.close(); } catch (Exception e) diff --git a/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterTest.java b/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterTest.java index cea67428617..b66a7b1ed70 100644 --- a/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterTest.java +++ b/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterTest.java @@ -1093,6 +1093,10 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte } public void testMaxSizeHighlight() throws Exception { + final MockAnalyzer analyzer = new MockAnalyzer(random, MockTokenizer.SIMPLE, true, MockTokenFilter.ENGLISH_STOPSET, true); + // we disable MockTokenizer checks because we will forcefully limit the + // tokenstream and call end() before incrementToken() returns false. + analyzer.setEnableChecks(false); TestHighlightRunner helper = new TestHighlightRunner() { @Override @@ -1122,7 +1126,10 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte public void run() throws Exception { String goodWord = "goodtoken"; CharacterRunAutomaton stopWords = new CharacterRunAutomaton(BasicAutomata.makeString("stoppedtoken")); - + // we disable MockTokenizer checks because we will forcefully limit the + // tokenstream and call end() before incrementToken() returns false. + final MockAnalyzer analyzer = new MockAnalyzer(random, MockTokenizer.SIMPLE, true, stopWords, true); + analyzer.setEnableChecks(false); TermQuery query = new TermQuery(new Term("data", goodWord)); String match; @@ -1134,13 +1141,13 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte sb.append("stoppedtoken"); } SimpleHTMLFormatter fm = new SimpleHTMLFormatter(); - Highlighter hg = getHighlighter(query, "data", new MockAnalyzer(random, MockTokenizer.SIMPLE, true, stopWords, true).tokenStream( + Highlighter hg = getHighlighter(query, "data", analyzer.tokenStream( "data", new StringReader(sb.toString())), fm);// new Highlighter(fm, // new // QueryTermScorer(query)); hg.setTextFragmenter(new NullFragmenter()); hg.setMaxDocCharsToAnalyze(100); - match = hg.getBestFragment(new MockAnalyzer(random, MockTokenizer.SIMPLE, true, stopWords, true), "data", sb.toString()); + match = hg.getBestFragment(analyzer, "data", sb.toString()); assertTrue("Matched text should be no more than 100 chars in length ", match.length() < hg .getMaxDocCharsToAnalyze()); @@ -1151,7 +1158,7 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte // + whitespace) sb.append(" "); sb.append(goodWord); - match = hg.getBestFragment(new MockAnalyzer(random, MockTokenizer.SIMPLE, true, stopWords, true), "data", sb.toString()); + match = hg.getBestFragment(analyzer, "data", sb.toString()); assertTrue("Matched text should be no more than 100 chars in length ", match.length() < hg .getMaxDocCharsToAnalyze()); } @@ -1726,6 +1733,11 @@ final class SynonymAnalyzer extends Analyzer { stream.addAttribute(CharTermAttribute.class); stream.addAttribute(PositionIncrementAttribute.class); stream.addAttribute(OffsetAttribute.class); + try { + stream.reset(); + } catch (IOException e) { + throw new RuntimeException(e); + } return new SynonymTokenizer(stream, synonyms); } } diff --git a/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/OffsetLimitTokenFilterTest.java b/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/OffsetLimitTokenFilterTest.java index 45aa3f51425..30dccc4bcc8 100644 --- a/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/OffsetLimitTokenFilterTest.java +++ b/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/OffsetLimitTokenFilterTest.java @@ -28,32 +28,38 @@ import org.apache.lucene.analysis.TokenStream; public class OffsetLimitTokenFilterTest extends BaseTokenStreamTestCase { public void testFilter() throws Exception { - TokenStream stream = new MockTokenizer(new StringReader( + // we disable MockTokenizer checks because we will forcefully limit the + // tokenstream and call end() before incrementToken() returns false. + MockTokenizer stream = new MockTokenizer(new StringReader( "short toolong evenmuchlongertext a ab toolong foo"), MockTokenizer.WHITESPACE, false); + stream.setEnableChecks(false); OffsetLimitTokenFilter filter = new OffsetLimitTokenFilter(stream, 10); assertTokenStreamContents(filter, new String[] {"short", "toolong"}); stream = new MockTokenizer(new StringReader( "short toolong evenmuchlongertext a ab toolong foo"), MockTokenizer.WHITESPACE, false); + stream.setEnableChecks(false); filter = new OffsetLimitTokenFilter(stream, 12); assertTokenStreamContents(filter, new String[] {"short", "toolong"}); stream = new MockTokenizer(new StringReader( "short toolong evenmuchlongertext a ab toolong foo"), MockTokenizer.WHITESPACE, false); + stream.setEnableChecks(false); filter = new OffsetLimitTokenFilter(stream, 30); assertTokenStreamContents(filter, new String[] {"short", "toolong", "evenmuchlongertext"}); - + // TODO: This is not actually testing reuse! (reusableTokenStream is not implemented) checkOneTermReuse(new Analyzer() { @Override public TokenStream tokenStream(String fieldName, Reader reader) { - return new OffsetLimitTokenFilter(new MockTokenizer(reader, - MockTokenizer.WHITESPACE, false), 10); + MockTokenizer tokenizer = new MockTokenizer(reader, MockTokenizer.WHITESPACE, false); + tokenizer.setEnableChecks(false); + return new OffsetLimitTokenFilter(tokenizer, 10); } }, "llenges", "llenges"); } diff --git a/lucene/contrib/queries/src/java/org/apache/lucene/search/FuzzyLikeThisQuery.java b/lucene/contrib/queries/src/java/org/apache/lucene/search/FuzzyLikeThisQuery.java index 113329abc4f..a50565cc2ed 100644 --- a/lucene/contrib/queries/src/java/org/apache/lucene/search/FuzzyLikeThisQuery.java +++ b/lucene/contrib/queries/src/java/org/apache/lucene/search/FuzzyLikeThisQuery.java @@ -192,6 +192,7 @@ public class FuzzyLikeThisQuery extends Query int corpusNumDocs=reader.numDocs(); Term internSavingTemplateTerm =new Term(f.fieldName); //optimization to avoid constructing new Term() objects HashSet processedTerms=new HashSet(); + ts.reset(); while (ts.incrementToken()) { String term = termAtt.toString(); @@ -244,7 +245,9 @@ public class FuzzyLikeThisQuery extends Query } } } - } + } + ts.end(); + ts.close(); } @Override diff --git a/lucene/contrib/queries/src/java/org/apache/lucene/search/similar/MoreLikeThis.java b/lucene/contrib/queries/src/java/org/apache/lucene/search/similar/MoreLikeThis.java index 3a944197752..c2387557947 100644 --- a/lucene/contrib/queries/src/java/org/apache/lucene/search/similar/MoreLikeThis.java +++ b/lucene/contrib/queries/src/java/org/apache/lucene/search/similar/MoreLikeThis.java @@ -885,7 +885,7 @@ public final class MoreLikeThis { int tokenCount=0; // for every token CharTermAttribute termAtt = ts.addAttribute(CharTermAttribute.class); - + ts.reset(); while (ts.incrementToken()) { String word = termAtt.toString(); tokenCount++; @@ -906,6 +906,8 @@ public final class MoreLikeThis { cnt.x++; } } + ts.end(); + ts.close(); } diff --git a/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/analyzing/AnalyzingQueryParser.java b/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/analyzing/AnalyzingQueryParser.java index 9d320a8532b..063a826217b 100644 --- a/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/analyzing/AnalyzingQueryParser.java +++ b/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/analyzing/AnalyzingQueryParser.java @@ -110,6 +110,11 @@ public class AnalyzingQueryParser extends org.apache.lucene.queryParser.QueryPar CharTermAttribute termAtt = source.addAttribute(CharTermAttribute.class); int countTokens = 0; + try { + source.reset(); + } catch (IOException e1) { + throw new RuntimeException(e1); + } while (true) { try { if (!source.incrementToken()) break; @@ -126,6 +131,7 @@ public class AnalyzingQueryParser extends org.apache.lucene.queryParser.QueryPar } } try { + source.end(); source.close(); } catch (IOException e) { // ignore @@ -191,7 +197,11 @@ public class AnalyzingQueryParser extends org.apache.lucene.queryParser.QueryPar TokenStream source = getAnalyzer().tokenStream(field, new StringReader(termStr)); List tlist = new ArrayList(); CharTermAttribute termAtt = source.addAttribute(CharTermAttribute.class); - + try { + source.reset(); + } catch (IOException e1) { + throw new RuntimeException(e1); + } while (true) { try { if (!source.incrementToken()) break; @@ -202,6 +212,7 @@ public class AnalyzingQueryParser extends org.apache.lucene.queryParser.QueryPar } try { + source.end(); source.close(); } catch (IOException e) { // ignore @@ -242,6 +253,7 @@ public class AnalyzingQueryParser extends org.apache.lucene.queryParser.QueryPar boolean multipleTokens = false; try { + source.reset(); if (source.incrementToken()) { nextToken = termAtt.toString(); } @@ -251,6 +263,7 @@ public class AnalyzingQueryParser extends org.apache.lucene.queryParser.QueryPar } try { + source.end(); source.close(); } catch (IOException e) { // ignore @@ -281,6 +294,7 @@ public class AnalyzingQueryParser extends org.apache.lucene.queryParser.QueryPar try { source = getAnalyzer().tokenStream(field, new StringReader(part1)); termAtt = source.addAttribute(CharTermAttribute.class); + source.reset(); multipleTokens = false; @@ -292,6 +306,7 @@ public class AnalyzingQueryParser extends org.apache.lucene.queryParser.QueryPar // ignore } try { + source.end(); source.close(); } catch (IOException e) { // ignore @@ -308,6 +323,7 @@ public class AnalyzingQueryParser extends org.apache.lucene.queryParser.QueryPar termAtt = source.addAttribute(CharTermAttribute.class); try { + source.reset(); if (source.incrementToken()) { part2 = termAtt.toString(); } @@ -316,6 +332,7 @@ public class AnalyzingQueryParser extends org.apache.lucene.queryParser.QueryPar // ignore } try { + source.end(); source.close(); } catch (IOException e) { // ignore diff --git a/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/processors/AnalyzerQueryNodeProcessor.java b/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/processors/AnalyzerQueryNodeProcessor.java index ea995156452..b0f61c543fc 100644 --- a/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/processors/AnalyzerQueryNodeProcessor.java +++ b/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/processors/AnalyzerQueryNodeProcessor.java @@ -123,6 +123,11 @@ public class AnalyzerQueryNodeProcessor extends QueryNodeProcessorImpl { TokenStream source = this.analyzer.tokenStream(field, new StringReader( text)); + try { + source.reset(); + } catch (IOException e1) { + throw new RuntimeException(e1); + } CachingTokenFilter buffer = new CachingTokenFilter(source); PositionIncrementAttribute posIncrAtt = null; diff --git a/lucene/contrib/wordnet/src/java/org/apache/lucene/wordnet/SynExpand.java b/lucene/contrib/wordnet/src/java/org/apache/lucene/wordnet/SynExpand.java index 646abf73dbd..871356c5cff 100755 --- a/lucene/contrib/wordnet/src/java/org/apache/lucene/wordnet/SynExpand.java +++ b/lucene/contrib/wordnet/src/java/org/apache/lucene/wordnet/SynExpand.java @@ -118,12 +118,14 @@ public final class SynExpand { // [1] Parse query into separate words so that when we expand we can avoid dups TokenStream ts = a.tokenStream( field, new StringReader( query)); CharTermAttribute termAtt = ts.addAttribute(CharTermAttribute.class); - + ts.reset(); while (ts.incrementToken()) { String word = termAtt.toString(); if ( already.add( word)) top.add( word); } + ts.end(); + ts.close(); final BooleanQuery tmp = new BooleanQuery(); // [2] form query diff --git a/lucene/contrib/wordnet/src/test/org/apache/lucene/wordnet/TestSynonymTokenFilter.java b/lucene/contrib/wordnet/src/test/org/apache/lucene/wordnet/TestSynonymTokenFilter.java index 89faf4b83af..6959a3ed0a8 100644 --- a/lucene/contrib/wordnet/src/test/org/apache/lucene/wordnet/TestSynonymTokenFilter.java +++ b/lucene/contrib/wordnet/src/test/org/apache/lucene/wordnet/TestSynonymTokenFilter.java @@ -111,7 +111,6 @@ public class TestSynonymTokenFilter extends BaseTokenStreamTestCase { setPreviousTokenStream(streams); } else { streams.source.reset(reader); - streams.result.reset(); // reset the SynonymTokenFilter } return streams.result; } diff --git a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/LikeThisQueryBuilder.java b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/LikeThisQueryBuilder.java index b96cf7bab4b..7a05ea717ba 100644 --- a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/LikeThisQueryBuilder.java +++ b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/LikeThisQueryBuilder.java @@ -80,9 +80,12 @@ public class LikeThisQueryBuilder implements QueryBuilder { CharTermAttribute termAtt = ts.addAttribute(CharTermAttribute.class); try { + ts.reset(); while(ts.incrementToken()) { stopWordsSet.add(termAtt.toString()); } + ts.end(); + ts.close(); } catch(IOException ioe) { diff --git a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/SpanOrTermsBuilder.java b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/SpanOrTermsBuilder.java index 1f8ddaebc97..822c79d598d 100644 --- a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/SpanOrTermsBuilder.java +++ b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/SpanOrTermsBuilder.java @@ -59,11 +59,14 @@ public class SpanOrTermsBuilder extends SpanBuilderBase TokenStream ts=analyzer.tokenStream(fieldName,new StringReader(value)); TermToBytesRefAttribute termAtt = ts.addAttribute(TermToBytesRefAttribute.class); BytesRef bytes = termAtt.getBytesRef(); + ts.reset(); while (ts.incrementToken()) { termAtt.fillBytesRef(); SpanTermQuery stq=new SpanTermQuery(new Term(fieldName, new BytesRef(bytes))); clausesList.add(stq); } + ts.end(); + ts.close(); SpanOrQuery soq=new SpanOrQuery(clausesList.toArray(new SpanQuery[clausesList.size()])); soq.setBoost(DOMUtils.getAttribute(e,"boost",1.0f)); return soq; diff --git a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/TermsFilterBuilder.java b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/TermsFilterBuilder.java index b1198389ccf..86521ff8042 100644 --- a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/TermsFilterBuilder.java +++ b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/TermsFilterBuilder.java @@ -64,6 +64,7 @@ public class TermsFilterBuilder implements FilterBuilder { Term term = null; BytesRef bytes = termAtt.getBytesRef(); + ts.reset(); while (ts.incrementToken()) { termAtt.fillBytesRef(); if (term == null) @@ -76,6 +77,8 @@ public class TermsFilterBuilder implements FilterBuilder } tf.addTerm(term); } + ts.end(); + ts.close(); } catch (IOException ioe) { diff --git a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/TermsQueryBuilder.java b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/TermsQueryBuilder.java index 051922e8a28..37ecf63e6b7 100644 --- a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/TermsQueryBuilder.java +++ b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/TermsQueryBuilder.java @@ -61,6 +61,7 @@ public class TermsQueryBuilder implements QueryBuilder { TermToBytesRefAttribute termAtt = ts.addAttribute(TermToBytesRefAttribute.class); Term term = null; BytesRef bytes = termAtt.getBytesRef(); + ts.reset(); while (ts.incrementToken()) { termAtt.fillBytesRef(); if (term == null) @@ -73,6 +74,8 @@ public class TermsQueryBuilder implements QueryBuilder { } bq.add(new BooleanClause(new TermQuery(term),BooleanClause.Occur.SHOULD)); } + ts.end(); + ts.close(); } catch (IOException ioe) { diff --git a/lucene/src/java/org/apache/lucene/queryParser/QueryParserBase.java b/lucene/src/java/org/apache/lucene/queryParser/QueryParserBase.java index eaf6d3f0126..58c77fd2897 100644 --- a/lucene/src/java/org/apache/lucene/queryParser/QueryParserBase.java +++ b/lucene/src/java/org/apache/lucene/queryParser/QueryParserBase.java @@ -806,6 +806,7 @@ public abstract class QueryParserBase { } try { + source.end(); source.close(); } catch (IOException ignored) {} diff --git a/lucene/src/test-framework/org/apache/lucene/analysis/BaseTokenStreamTestCase.java b/lucene/src/test-framework/org/apache/lucene/analysis/BaseTokenStreamTestCase.java index 4d4141c6ab3..c5bb9f26448 100644 --- a/lucene/src/test-framework/org/apache/lucene/analysis/BaseTokenStreamTestCase.java +++ b/lucene/src/test-framework/org/apache/lucene/analysis/BaseTokenStreamTestCase.java @@ -262,6 +262,7 @@ public abstract class BaseTokenStreamTestCase extends LuceneTestCase { tokens.add(termAtt.toString()); // TODO: we could collect offsets etc here for better checking that reset() really works. } + ts.end(); ts.close(); // verify reusing is "reproducable" and also get the normal tokenstream sanity checks if (!tokens.isEmpty()) diff --git a/lucene/src/test-framework/org/apache/lucene/analysis/MockAnalyzer.java b/lucene/src/test-framework/org/apache/lucene/analysis/MockAnalyzer.java index ae889c1c3b1..3818d071f99 100644 --- a/lucene/src/test-framework/org/apache/lucene/analysis/MockAnalyzer.java +++ b/lucene/src/test-framework/org/apache/lucene/analysis/MockAnalyzer.java @@ -36,6 +36,7 @@ public final class MockAnalyzer extends Analyzer { private int positionIncrementGap; private final Random random; private Map previousMappings = new HashMap(); + private boolean enableChecks = true; /** * Creates a new MockAnalyzer. @@ -75,6 +76,7 @@ public final class MockAnalyzer extends Analyzer { @Override public TokenStream tokenStream(String fieldName, Reader reader) { MockTokenizer tokenizer = new MockTokenizer(reader, runAutomaton, lowerCase); + tokenizer.setEnableChecks(enableChecks); TokenFilter filt = new MockTokenFilter(tokenizer, filter, enablePositionIncrements); filt = maybePayload(filt, fieldName); return filt; @@ -98,13 +100,13 @@ public final class MockAnalyzer extends Analyzer { if (saved == null) { saved = new SavedStreams(); saved.tokenizer = new MockTokenizer(reader, runAutomaton, lowerCase); + saved.tokenizer.setEnableChecks(enableChecks); saved.filter = new MockTokenFilter(saved.tokenizer, filter, enablePositionIncrements); saved.filter = maybePayload(saved.filter, fieldName); map.put(fieldName, saved); return saved.filter; } else { saved.tokenizer.reset(reader); - saved.filter.reset(); return saved.filter; } } @@ -139,4 +141,12 @@ public final class MockAnalyzer extends Analyzer { public int getPositionIncrementGap(String fieldName){ return positionIncrementGap; } + + /** + * Toggle consumer workflow checking: if your test consumes tokenstreams normally you + * should leave this enabled. + */ + public void setEnableChecks(boolean enableChecks) { + this.enableChecks = enableChecks; + } } diff --git a/lucene/src/test-framework/org/apache/lucene/analysis/MockPayloadAnalyzer.java b/lucene/src/test-framework/org/apache/lucene/analysis/MockPayloadAnalyzer.java index 63d99af28c6..fe64ad8884e 100644 --- a/lucene/src/test-framework/org/apache/lucene/analysis/MockPayloadAnalyzer.java +++ b/lucene/src/test-framework/org/apache/lucene/analysis/MockPayloadAnalyzer.java @@ -86,6 +86,7 @@ final class MockPayloadFilter extends TokenFilter { @Override public void reset() throws IOException { + super.reset(); i = 0; pos = 0; } diff --git a/lucene/src/test-framework/org/apache/lucene/analysis/MockTokenizer.java b/lucene/src/test-framework/org/apache/lucene/analysis/MockTokenizer.java index f5bc45996a0..15e501f0f41 100644 --- a/lucene/src/test-framework/org/apache/lucene/analysis/MockTokenizer.java +++ b/lucene/src/test-framework/org/apache/lucene/analysis/MockTokenizer.java @@ -50,11 +50,27 @@ public class MockTokenizer extends Tokenizer { private final OffsetAttribute offsetAtt = addAttribute(OffsetAttribute.class); int off = 0; + // TODO: "register" with LuceneTestCase to ensure all streams are closed() ? + // currently, we can only check that the lifecycle is correct if someone is reusing, + // but not for "one-offs". + private static enum State { + SETREADER, // consumer set a reader input either via ctor or via reset(Reader) + RESET, // consumer has called reset() + INCREMENT, // consumer is consuming, has called incrementToken() == true + INCREMENT_FALSE, // consumer has called incrementToken() which returned false + END, // consumer has called end() to perform end of stream operations + CLOSE // consumer has called close() to release any resources + }; + + private State streamState = State.CLOSE; + private boolean enableChecks = true; + public MockTokenizer(AttributeFactory factory, Reader input, CharacterRunAutomaton runAutomaton, boolean lowerCase) { super(factory, input); this.runAutomaton = runAutomaton; this.lowerCase = lowerCase; this.state = runAutomaton.getInitialState(); + this.streamState = State.SETREADER; } public MockTokenizer(Reader input, CharacterRunAutomaton runAutomaton, boolean lowerCase) { @@ -62,10 +78,13 @@ public class MockTokenizer extends Tokenizer { this.runAutomaton = runAutomaton; this.lowerCase = lowerCase; this.state = runAutomaton.getInitialState(); + this.streamState = State.SETREADER; } @Override public final boolean incrementToken() throws IOException { + assert !enableChecks || (streamState == State.RESET || streamState == State.INCREMENT) + : "incrementToken() called while in wrong state: " + streamState; clearAttributes(); for (;;) { int startOffset = off; @@ -82,9 +101,11 @@ public class MockTokenizer extends Tokenizer { cp = readCodePoint(); } while (cp >= 0 && isTokenChar(cp)); offsetAtt.setOffset(startOffset, endOffset); + streamState = State.INCREMENT; return true; } } + streamState = State.INCREMENT_FALSE; return false; } @@ -126,11 +147,42 @@ public class MockTokenizer extends Tokenizer { super.reset(); state = runAutomaton.getInitialState(); off = 0; + assert !enableChecks || streamState != State.RESET : "double reset()"; + streamState = State.RESET; + } + + @Override + public void close() throws IOException { + super.close(); + // in some exceptional cases (e.g. TestIndexWriterExceptions) a test can prematurely close() + // these tests should disable this check, by default we check the normal workflow. + // TODO: investigate the CachingTokenFilter "double-close"... for now we ignore this + assert !enableChecks || streamState == State.END || streamState == State.CLOSE : "close() called in wrong state: " + streamState; + streamState = State.CLOSE; + } + + @Override + public void reset(Reader input) throws IOException { + super.reset(input); + assert !enableChecks || streamState == State.CLOSE : "setReader() called in wrong state: " + streamState; + streamState = State.SETREADER; } @Override public void end() throws IOException { int finalOffset = correctOffset(off); offsetAtt.setOffset(finalOffset, finalOffset); + // some tokenizers, such as limiting tokenizers, call end() before incrementToken() returns false. + // these tests should disable this check (in general you should consume the entire stream) + assert !enableChecks || streamState == State.INCREMENT_FALSE : "end() called before incrementToken() returned false!"; + streamState = State.END; + } + + /** + * Toggle consumer workflow checking: if your test consumes tokenstreams normally you + * should leave this enabled. + */ + public void setEnableChecks(boolean enableChecks) { + this.enableChecks = enableChecks; } } diff --git a/lucene/src/test/org/apache/lucene/analysis/TestMockAnalyzer.java b/lucene/src/test/org/apache/lucene/analysis/TestMockAnalyzer.java index e5ec6fad862..4df9f1f456f 100644 --- a/lucene/src/test/org/apache/lucene/analysis/TestMockAnalyzer.java +++ b/lucene/src/test/org/apache/lucene/analysis/TestMockAnalyzer.java @@ -107,6 +107,7 @@ public class TestMockAnalyzer extends BaseTokenStreamTestCase { // consume } stream.end(); + stream.close(); assertAnalyzesToReuse(analyzer, testString, new String[] { "t" }); } diff --git a/lucene/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java b/lucene/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java index 4769319accf..4c3e6c98e15 100644 --- a/lucene/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java +++ b/lucene/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java @@ -155,7 +155,9 @@ public class TestIndexWriterExceptions extends LuceneTestCase { } MockDirectoryWrapper dir = newDirectory(); - MockIndexWriter writer = new MockIndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)) + MockAnalyzer analyzer = new MockAnalyzer(random); + analyzer.setEnableChecks(false); // disable workflow checking as we forcefully close() in exceptional cases. + MockIndexWriter writer = new MockIndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, analyzer) .setRAMBufferSizeMB(0.1).setMergeScheduler(new ConcurrentMergeScheduler())); ((ConcurrentMergeScheduler) writer.getConfig().getMergeScheduler()).setSuppressExceptions(); //writer.setMaxBufferedDocs(10); @@ -201,7 +203,9 @@ public class TestIndexWriterExceptions extends LuceneTestCase { public void testRandomExceptionsThreads() throws Throwable { MockDirectoryWrapper dir = newDirectory(); - MockIndexWriter writer = new MockIndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)) + MockAnalyzer analyzer = new MockAnalyzer(random); + analyzer.setEnableChecks(false); // disable workflow checking as we forcefully close() in exceptional cases. + MockIndexWriter writer = new MockIndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, analyzer) .setRAMBufferSizeMB(0.2).setMergeScheduler(new ConcurrentMergeScheduler())); ((ConcurrentMergeScheduler) writer.getConfig().getMergeScheduler()).setSuppressExceptions(); //writer.setMaxBufferedDocs(10); @@ -321,7 +325,9 @@ public class TestIndexWriterExceptions extends LuceneTestCase { Analyzer analyzer = new Analyzer() { @Override public TokenStream tokenStream(String fieldName, Reader reader) { - return new CrashingFilter(fieldName, new MockTokenizer(reader, MockTokenizer.WHITESPACE, false)); + MockTokenizer tokenizer = new MockTokenizer(reader, MockTokenizer.WHITESPACE, false); + tokenizer.setEnableChecks(false); // disable workflow checking as we forcefully close() in exceptional cases. + return new CrashingFilter(fieldName, tokenizer); } }; @@ -390,7 +396,9 @@ public class TestIndexWriterExceptions extends LuceneTestCase { @Override public TokenStream tokenStream(String fieldName, Reader reader) { - return new TokenFilter(new MockTokenizer(reader, MockTokenizer.SIMPLE, true)) { + MockTokenizer tokenizer = new MockTokenizer(reader, MockTokenizer.SIMPLE, true); + tokenizer.setEnableChecks(false); // disable workflow checking as we forcefully close() in exceptional cases. + return new TokenFilter(tokenizer) { private int count = 0; @Override @@ -522,7 +530,9 @@ public class TestIndexWriterExceptions extends LuceneTestCase { Analyzer analyzer = new Analyzer() { @Override public TokenStream tokenStream(String fieldName, Reader reader) { - return new CrashingFilter(fieldName, new MockTokenizer(reader, MockTokenizer.WHITESPACE, false)); + MockTokenizer tokenizer = new MockTokenizer(reader, MockTokenizer.WHITESPACE, false); + tokenizer.setEnableChecks(false); // disable workflow checking as we forcefully close() in exceptional cases. + return new CrashingFilter(fieldName, tokenizer); } }; @@ -621,7 +631,9 @@ public class TestIndexWriterExceptions extends LuceneTestCase { Analyzer analyzer = new Analyzer() { @Override public TokenStream tokenStream(String fieldName, Reader reader) { - return new CrashingFilter(fieldName, new MockTokenizer(reader, MockTokenizer.WHITESPACE, false)); + MockTokenizer tokenizer = new MockTokenizer(reader, MockTokenizer.WHITESPACE, false); + tokenizer.setEnableChecks(false); // disable workflow checking as we forcefully close() in exceptional cases. + return new CrashingFilter(fieldName, tokenizer); } }; diff --git a/lucene/src/test/org/apache/lucene/index/TestLongPostings.java b/lucene/src/test/org/apache/lucene/index/TestLongPostings.java index fbe6fa1e0f4..1d745d7d8f0 100644 --- a/lucene/src/test/org/apache/lucene/index/TestLongPostings.java +++ b/lucene/src/test/org/apache/lucene/index/TestLongPostings.java @@ -49,6 +49,7 @@ public class TestLongPostings extends LuceneTestCase { final TermToBytesRefAttribute termAtt = ts.getAttribute(TermToBytesRefAttribute.class); final BytesRef termBytes = termAtt.getBytesRef(); int count = 0; + ts.reset(); while(ts.incrementToken()) { termAtt.fillBytesRef(); if (count == 0 && !termBytes.utf8ToString().equals(s)) { diff --git a/lucene/src/test/org/apache/lucene/index/TestTermVectorsWriter.java b/lucene/src/test/org/apache/lucene/index/TestTermVectorsWriter.java index d41c0793a1f..350a05b6c9b 100644 --- a/lucene/src/test/org/apache/lucene/index/TestTermVectorsWriter.java +++ b/lucene/src/test/org/apache/lucene/index/TestTermVectorsWriter.java @@ -121,7 +121,9 @@ public class TestTermVectorsWriter extends LuceneTestCase { Analyzer analyzer = new MockAnalyzer(random); IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, analyzer)); Document doc = new Document(); - TokenStream stream = new CachingTokenFilter(analyzer.tokenStream("field", new StringReader("abcd "))); + TokenStream stream = analyzer.tokenStream("field", new StringReader("abcd ")); + stream.reset(); // TODO: wierd to reset before wrapping with CachingTokenFilter... correct? + stream = new CachingTokenFilter(stream); Field f = new Field("field", stream, Field.TermVector.WITH_POSITIONS_OFFSETS); doc.add(f); doc.add(f); diff --git a/lucene/src/test/org/apache/lucene/search/TestPhraseQuery.java b/lucene/src/test/org/apache/lucene/search/TestPhraseQuery.java index 74b8a1b08f9..48efc27e2b5 100644 --- a/lucene/src/test/org/apache/lucene/search/TestPhraseQuery.java +++ b/lucene/src/test/org/apache/lucene/search/TestPhraseQuery.java @@ -626,11 +626,14 @@ public class TestPhraseQuery extends LuceneTestCase { } TokenStream ts = analyzer.reusableTokenStream("ignore", new StringReader(term)); CharTermAttribute termAttr = ts.addAttribute(CharTermAttribute.class); + ts.reset(); while(ts.incrementToken()) { String text = termAttr.toString(); doc.add(text); sb.append(text).append(' '); } + ts.end(); + ts.close(); } else { // pick existing sub-phrase List lastDoc = docs.get(r.nextInt(docs.size())); From 33eb3e534e1403e78c2047b18fc2fb3c2597cd56 Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Thu, 12 May 2011 16:54:45 +0000 Subject: [PATCH 55/57] LUCENE-3087: fix highlighter case that prevented highlighting exact phrase when tokens overlap git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1102377 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/contrib/CHANGES.txt | 4 + .../lucene/search/highlight/TokenSources.java | 27 +++-- .../search/highlight/TokenSourcesTest.java | 108 +++++++++++++++++- 3 files changed, 123 insertions(+), 16 deletions(-) diff --git a/lucene/contrib/CHANGES.txt b/lucene/contrib/CHANGES.txt index 2e6021bf090..3c553a67694 100644 --- a/lucene/contrib/CHANGES.txt +++ b/lucene/contrib/CHANGES.txt @@ -188,6 +188,10 @@ Bug fixes * LUCENE-2943: Fix thread-safety issues with ICUCollationKeyFilter. (Robert Muir) + * LUCENE-3087: Highlighter: fix case that was preventing highlighting + of exact phrase when tokens overlap. (Pierre Gossé via Mike + McCandless) + API Changes * LUCENE-2867: Some contrib queryparser methods that receives CharSequence as diff --git a/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/TokenSources.java b/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/TokenSources.java index 9a9294f93fd..536c7e20465 100644 --- a/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/TokenSources.java +++ b/lucene/contrib/highlighter/src/java/org/apache/lucene/search/highlight/TokenSources.java @@ -30,6 +30,7 @@ import org.apache.lucene.analysis.Token; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.TermFreqVector; @@ -158,10 +159,13 @@ public class TokenSources { OffsetAttribute offsetAtt; + PositionIncrementAttribute posincAtt; + StoredTokenStream(Token tokens[]) { this.tokens = tokens; termAtt = addAttribute(CharTermAttribute.class); offsetAtt = addAttribute(OffsetAttribute.class); + posincAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class); } @Override @@ -173,6 +177,10 @@ public class TokenSources { clearAttributes(); termAtt.setEmpty().append(token); offsetAtt.setOffset(token.startOffset(), token.endOffset()); + posincAtt + .setPositionIncrement(currentToken <= 1 + || tokens[currentToken - 1].startOffset() > tokens[currentToken - 2] + .startOffset() ? 1 : 0); return true; } } @@ -180,7 +188,6 @@ public class TokenSources { BytesRef[] terms = tpv.getTerms(); int[] freq = tpv.getTermFrequencies(); int totalTokens = 0; - for (int t = 0; t < freq.length; t++) { totalTokens += freq[t]; } @@ -189,7 +196,8 @@ public class TokenSources { for (int t = 0; t < freq.length; t++) { TermVectorOffsetInfo[] offsets = tpv.getOffsets(t); if (offsets == null) { - throw new IllegalArgumentException("Required TermVector Offset information was not found"); + throw new IllegalArgumentException( + "Required TermVector Offset information was not found"); } int[] pos = null; @@ -205,8 +213,8 @@ public class TokenSources { unsortedTokens = new ArrayList(); } for (int tp = 0; tp < offsets.length; tp++) { - Token token = new Token(terms[t].utf8ToString(), offsets[tp].getStartOffset(), offsets[tp] - .getEndOffset()); + Token token = new Token(terms[t].utf8ToString(), + offsets[tp].getStartOffset(), offsets[tp].getEndOffset()); unsortedTokens.add(token); } } else { @@ -221,8 +229,8 @@ public class TokenSources { // tokens stored with positions - can use this to index straight into // sorted array for (int tp = 0; tp < pos.length; tp++) { - Token token = new Token(terms[t].utf8ToString(), offsets[tp].getStartOffset(), - offsets[tp].getEndOffset()); + Token token = new Token(terms[t].utf8ToString(), + offsets[tp].getStartOffset(), offsets[tp].getEndOffset()); tokensInOriginalOrder[pos[tp]] = token; } } @@ -233,10 +241,9 @@ public class TokenSources { .size()]); ArrayUtil.mergeSort(tokensInOriginalOrder, new Comparator() { public int compare(Token t1, Token t2) { - if (t1.startOffset() == t2.startOffset()) - return t1.endOffset() - t2.endOffset(); - else - return t1.startOffset() - t2.startOffset(); + if (t1.startOffset() == t2.startOffset()) return t1.endOffset() + - t2.endOffset(); + else return t1.startOffset() - t2.startOffset(); } }); } diff --git a/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/TokenSourcesTest.java b/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/TokenSourcesTest.java index 572aa219b78..02dd92d40e0 100644 --- a/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/TokenSourcesTest.java +++ b/lucene/contrib/highlighter/src/test/org/apache/lucene/search/highlight/TokenSourcesTest.java @@ -36,7 +36,10 @@ import org.apache.lucene.index.Term; import org.apache.lucene.index.TermPositionVector; import org.apache.lucene.search.DisjunctionMaxQuery; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; import org.apache.lucene.search.TopDocs; +import org.apache.lucene.search.spans.SpanNearQuery; +import org.apache.lucene.search.spans.SpanQuery; import org.apache.lucene.search.spans.SpanTermQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.store.LockObtainFailedException; @@ -86,12 +89,12 @@ public class TokenSourcesTest extends LuceneTestCase { public void reset() { this.i = -1; this.tokens = new Token[] { - new Token(new char[] { 't', 'h', 'e' }, 0, 3, 0, 3), - new Token(new char[] { '{', 'f', 'o', 'x', '}' }, 0, 5, 0, 7), - new Token(new char[] { 'f', 'o', 'x' }, 0, 3, 4, 7), - new Token(new char[] { 'd', 'i', 'd' }, 0, 3, 8, 11), - new Token(new char[] { 'n', 'o', 't' }, 0, 3, 12, 15), - new Token(new char[] { 'j', 'u', 'm', 'p' }, 0, 4, 16, 20) }; + new Token(new char[] {'t', 'h', 'e'}, 0, 3, 0, 3), + new Token(new char[] {'{', 'f', 'o', 'x', '}'}, 0, 5, 0, 7), + new Token(new char[] {'f', 'o', 'x'}, 0, 3, 4, 7), + new Token(new char[] {'d', 'i', 'd'}, 0, 3, 8, 11), + new Token(new char[] {'n', 'o', 't'}, 0, 3, 12, 15), + new Token(new char[] {'j', 'u', 'm', 'p'}, 0, 4, 16, 20)}; this.tokens[1].setPositionIncrement(0); } } @@ -188,4 +191,97 @@ public class TokenSourcesTest extends LuceneTestCase { } } + public void testOverlapWithOffsetExactPhrase() throws CorruptIndexException, + LockObtainFailedException, IOException, InvalidTokenOffsetsException { + final String TEXT = "the fox did not jump"; + final Directory directory = newDirectory(); + final IndexWriter indexWriter = new IndexWriter(directory, + newIndexWriterConfig(TEST_VERSION_CURRENT, new OverlapAnalyzer())); + try { + final Document document = new Document(); + document.add(new Field(FIELD, new TokenStreamOverlap(), + TermVector.WITH_OFFSETS)); + indexWriter.addDocument(document); + } finally { + indexWriter.close(); + } + final IndexReader indexReader = IndexReader.open(directory, true); + try { + assertEquals(1, indexReader.numDocs()); + final IndexSearcher indexSearcher = newSearcher(indexReader); + try { + // final DisjunctionMaxQuery query = new DisjunctionMaxQuery(1); + // query.add(new SpanTermQuery(new Term(FIELD, "{fox}"))); + // query.add(new SpanTermQuery(new Term(FIELD, "fox"))); + final Query phraseQuery = new SpanNearQuery(new SpanQuery[] { + new SpanTermQuery(new Term(FIELD, "the")), + new SpanTermQuery(new Term(FIELD, "fox"))}, 0, true); + + TopDocs hits = indexSearcher.search(phraseQuery, 1); + assertEquals(1, hits.totalHits); + final Highlighter highlighter = new Highlighter( + new SimpleHTMLFormatter(), new SimpleHTMLEncoder(), + new QueryScorer(phraseQuery)); + final TokenStream tokenStream = TokenSources + .getTokenStream( + (TermPositionVector) indexReader.getTermFreqVector(0, FIELD), + false); + assertEquals("the fox did not jump", + highlighter.getBestFragment(tokenStream, TEXT)); + } finally { + indexSearcher.close(); + } + } finally { + indexReader.close(); + directory.close(); + } + } + + public void testOverlapWithPositionsAndOffsetExactPhrase() + throws CorruptIndexException, LockObtainFailedException, IOException, + InvalidTokenOffsetsException { + final String TEXT = "the fox did not jump"; + final Directory directory = newDirectory(); + final IndexWriter indexWriter = new IndexWriter(directory, + newIndexWriterConfig(TEST_VERSION_CURRENT, new OverlapAnalyzer())); + try { + final Document document = new Document(); + document.add(new Field(FIELD, new TokenStreamOverlap(), + TermVector.WITH_POSITIONS_OFFSETS)); + indexWriter.addDocument(document); + } finally { + indexWriter.close(); + } + final IndexReader indexReader = IndexReader.open(directory, true); + try { + assertEquals(1, indexReader.numDocs()); + final IndexSearcher indexSearcher = newSearcher(indexReader); + try { + // final DisjunctionMaxQuery query = new DisjunctionMaxQuery(1); + // query.add(new SpanTermQuery(new Term(FIELD, "the"))); + // query.add(new SpanTermQuery(new Term(FIELD, "fox"))); + final Query phraseQuery = new SpanNearQuery(new SpanQuery[] { + new SpanTermQuery(new Term(FIELD, "the")), + new SpanTermQuery(new Term(FIELD, "fox"))}, 0, true); + + TopDocs hits = indexSearcher.search(phraseQuery, 1); + assertEquals(1, hits.totalHits); + final Highlighter highlighter = new Highlighter( + new SimpleHTMLFormatter(), new SimpleHTMLEncoder(), + new QueryScorer(phraseQuery)); + final TokenStream tokenStream = TokenSources + .getTokenStream( + (TermPositionVector) indexReader.getTermFreqVector(0, FIELD), + false); + assertEquals("the fox did not jump", + highlighter.getBestFragment(tokenStream, TEXT)); + } finally { + indexSearcher.close(); + } + } finally { + indexReader.close(); + directory.close(); + } + } + } From 07adbebc44478c023463d9289ca779022a7abc9c Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Thu, 12 May 2011 17:13:30 +0000 Subject: [PATCH 56/57] LUCENE-3058: allow FST to map single input to more than one output; add concrete outputs impl that supports 1 or 2 ints git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1102384 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/util/automaton/fst/Builder.java | 16 +- .../apache/lucene/util/automaton/fst/FST.java | 9 +- .../lucene/util/automaton/fst/Outputs.java | 4 + .../automaton/fst/PositiveIntOutputs.java | 7 +- .../fst/UpToTwoPositiveIntOutputs.java | 224 ++++++++++++++++++ .../lucene/util/automaton/fst/TestFSTs.java | 51 +++- 6 files changed, 294 insertions(+), 17 deletions(-) create mode 100644 lucene/src/java/org/apache/lucene/util/automaton/fst/UpToTwoPositiveIntOutputs.java diff --git a/lucene/src/java/org/apache/lucene/util/automaton/fst/Builder.java b/lucene/src/java/org/apache/lucene/util/automaton/fst/Builder.java index fed8cd21098..19949170936 100644 --- a/lucene/src/java/org/apache/lucene/util/automaton/fst/Builder.java +++ b/lucene/src/java/org/apache/lucene/util/automaton/fst/Builder.java @@ -261,9 +261,12 @@ public class Builder { add(scratchIntsRef, output); } + /** It's OK to add the same input twice in a row with + * different outputs, as long as outputs impls the merge + * method. */ public void add(IntsRef input, T output) throws IOException { //System.out.println("\nFST ADD: input=" + input + " output=" + fst.outputs.outputToString(output)); - assert lastInput.length == 0 || input.compareTo(lastInput) > 0: "inputs are added out of order lastInput=" + lastInput + " vs input=" + input; + assert lastInput.length == 0 || input.compareTo(lastInput) >= 0: "inputs are added out of order lastInput=" + lastInput + " vs input=" + input; assert validOutput(output); //System.out.println("\nadd: " + input); @@ -347,8 +350,15 @@ public class Builder { assert validOutput(output); } - // push remaining output: - frontier[prefixLenPlus1-1].setLastOutput(input.ints[input.offset + prefixLenPlus1-1], output); + if (lastInput.length == input.length && prefixLenPlus1 == 1+input.length) { + // same input more than 1 time in a row, mapping to + // multiple outputs + lastNode.output = fst.outputs.merge(lastNode.output, output); + } else { + // this new arc is private to this new input; set its + // arc output to the leftover output: + frontier[prefixLenPlus1-1].setLastOutput(input.ints[input.offset + prefixLenPlus1-1], output); + } // save last input lastInput.copy(input); diff --git a/lucene/src/java/org/apache/lucene/util/automaton/fst/FST.java b/lucene/src/java/org/apache/lucene/util/automaton/fst/FST.java index 512d07f28d7..dbce4c011c3 100644 --- a/lucene/src/java/org/apache/lucene/util/automaton/fst/FST.java +++ b/lucene/src/java/org/apache/lucene/util/automaton/fst/FST.java @@ -231,10 +231,13 @@ public class FST { } void setEmptyOutput(T v) throws IOException { - if (emptyOutput != null && !emptyOutput.equals(v)) { - throw new IllegalStateException("empty output is already set: " + outputs.outputToString(emptyOutput) + " vs " + outputs.outputToString(v)); + if (emptyOutput != null) { + if (!emptyOutput.equals(v)) { + emptyOutput = outputs.merge(emptyOutput, v); + } + } else { + emptyOutput = v; } - emptyOutput = v; // TODO: this is messy -- replace with sillyBytesWriter; maybe make // bytes private diff --git a/lucene/src/java/org/apache/lucene/util/automaton/fst/Outputs.java b/lucene/src/java/org/apache/lucene/util/automaton/fst/Outputs.java index 18f4dc29432..66efc3ff008 100644 --- a/lucene/src/java/org/apache/lucene/util/automaton/fst/Outputs.java +++ b/lucene/src/java/org/apache/lucene/util/automaton/fst/Outputs.java @@ -54,4 +54,8 @@ public abstract class Outputs { public abstract T getNoOutput(); public abstract String outputToString(T output); + + public T merge(T first, T second) { + throw new UnsupportedOperationException(); + } } diff --git a/lucene/src/java/org/apache/lucene/util/automaton/fst/PositiveIntOutputs.java b/lucene/src/java/org/apache/lucene/util/automaton/fst/PositiveIntOutputs.java index ba17fe99dee..984324e07ce 100644 --- a/lucene/src/java/org/apache/lucene/util/automaton/fst/PositiveIntOutputs.java +++ b/lucene/src/java/org/apache/lucene/util/automaton/fst/PositiveIntOutputs.java @@ -22,14 +22,11 @@ import java.io.IOException; import org.apache.lucene.store.DataInput; import org.apache.lucene.store.DataOutput; -// TODO: make a sharing and non-sharing variant; eg if you -// output docFreq per term the FST will be smaller if you -// don't share since they are not "well shared" - /** * Output is a long, for each input term. NOTE: the * resulting FST is not guaranteed to be minimal! See - * {@link Builder}. + * {@link Builder}. You cannot store 0 output with this + * (that's reserved to mean "no output")! * @lucene.experimental */ diff --git a/lucene/src/java/org/apache/lucene/util/automaton/fst/UpToTwoPositiveIntOutputs.java b/lucene/src/java/org/apache/lucene/util/automaton/fst/UpToTwoPositiveIntOutputs.java new file mode 100644 index 00000000000..0c388d28710 --- /dev/null +++ b/lucene/src/java/org/apache/lucene/util/automaton/fst/UpToTwoPositiveIntOutputs.java @@ -0,0 +1,224 @@ +package org.apache.lucene.util.automaton.fst; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; + +import org.apache.lucene.store.DataInput; +import org.apache.lucene.store.DataOutput; + +/** + * Holds one or two longs for each input term. If it's a + * single output, Long is returned; else, TwoLongs. Order + * is preseved in the TwoLongs case, ie .first is the first + * input/output added to Builder, and .second is the + * second. You cannot store 0 output with this (that's + * reserved to mean "no output")! + * + * NOTE: the resulting FST is not guaranteed to be minimal! + * See {@link Builder}. + * + * @lucene.experimental + */ + +public final class UpToTwoPositiveIntOutputs extends Outputs { + + public final static class TwoLongs { + final long first; + final long second; + + public TwoLongs(long first, long second) { + this.first = first; + this.second = second; + assert first >= 0; + assert second >= 0; + } + + @Override + public String toString() { + return "TwoLongs:" + first + "," + second; + } + + @Override + public boolean equals(Object _other) { + if (_other instanceof TwoLongs) { + final TwoLongs other = (TwoLongs) _other; + return first == other.first && second == other.second; + } else { + return false; + } + } + + @Override + public int hashCode() { + return (int) ((first^(first>>>32)) ^ (second^(second>>32))); + } + } + + private final static Long NO_OUTPUT = new Long(0); + + private final boolean doShare; + + private final static UpToTwoPositiveIntOutputs singletonShare = new UpToTwoPositiveIntOutputs(true); + private final static UpToTwoPositiveIntOutputs singletonNoShare = new UpToTwoPositiveIntOutputs(false); + + private UpToTwoPositiveIntOutputs(boolean doShare) { + this.doShare = doShare; + } + + public static UpToTwoPositiveIntOutputs getSingleton(boolean doShare) { + return doShare ? singletonShare : singletonNoShare; + } + + public Long get(long v) { + if (v == 0) { + return NO_OUTPUT; + } else { + return Long.valueOf(v); + } + } + + public TwoLongs get(long first, long second) { + return new TwoLongs(first, second); + } + + @Override + public Long common(Object _output1, Object _output2) { + assert valid(_output1, false); + assert valid(_output2, false); + final Long output1 = (Long) _output1; + final Long output2 = (Long) _output2; + if (output1 == NO_OUTPUT || output2 == NO_OUTPUT) { + return NO_OUTPUT; + } else if (doShare) { + assert output1 > 0; + assert output2 > 0; + return Math.min(output1, output2); + } else if (output1.equals(output2)) { + return output1; + } else { + return NO_OUTPUT; + } + } + + @Override + public Long subtract(Object _output, Object _inc) { + assert valid(_output, false); + assert valid(_inc, false); + final Long output = (Long) _output; + final Long inc = (Long) _inc; + assert output >= inc; + + if (inc == NO_OUTPUT) { + return output; + } else if (output.equals(inc)) { + return NO_OUTPUT; + } else { + return output - inc; + } + } + + @Override + public Object add(Object _prefix, Object _output) { + assert valid(_prefix, false); + assert valid(_output, true); + final Long prefix = (Long) _prefix; + if (_output instanceof Long) { + final Long output = (Long) _output; + if (prefix == NO_OUTPUT) { + return output; + } else if (output == NO_OUTPUT) { + return prefix; + } else { + return prefix + output; + } + } else { + final TwoLongs output = (TwoLongs) _output; + final long v = prefix; + return new TwoLongs(output.first + v, output.second + v); + } + } + + @Override + public void write(Object _output, DataOutput out) throws IOException { + assert valid(_output, true); + if (_output instanceof Long) { + final Long output = (Long) _output; + out.writeVLong(output<<1); + } else { + final TwoLongs output = (TwoLongs) _output; + out.writeVLong((output.first<<1) | 1); + out.writeVLong(output.second); + } + } + + @Override + public Object read(DataInput in) throws IOException { + final long code = in.readVLong(); + if ((code & 1) == 0) { + // single long + final long v = code >>> 1; + if (v == 0) { + return NO_OUTPUT; + } else { + return Long.valueOf(v); + } + } else { + // two longs + final long first = code >>> 1; + final long second = in.readVLong(); + return new TwoLongs(first, second); + } + } + + private boolean valid(Long o) { + assert o != null; + assert o instanceof Long; + assert o == NO_OUTPUT || o > 0; + return true; + } + + // Used only by assert + private boolean valid(Object _o, boolean allowDouble) { + if (!allowDouble) { + assert _o instanceof Long; + return valid((Long) _o); + } else if (_o instanceof TwoLongs) { + return true; + } else { + return valid((Long) _o); + } + } + + @Override + public Object getNoOutput() { + return NO_OUTPUT; + } + + @Override + public String outputToString(Object output) { + return output.toString(); + } + + @Override + public Object merge(Object first, Object second) { + assert valid(first, false); + assert valid(second, false); + return new TwoLongs((Long) first, (Long) second); + } +} diff --git a/lucene/src/test/org/apache/lucene/util/automaton/fst/TestFSTs.java b/lucene/src/test/org/apache/lucene/util/automaton/fst/TestFSTs.java index b440d5ac7ea..4798f6f64be 100644 --- a/lucene/src/test/org/apache/lucene/util/automaton/fst/TestFSTs.java +++ b/lucene/src/test/org/apache/lucene/util/automaton/fst/TestFSTs.java @@ -288,6 +288,36 @@ public class TestFSTs extends LuceneTestCase { } new FSTTester(random, dir, inputMode, pairs, outputs).doTest(); } + + // Up to two positive ints, shared, generally but not + // monotonically increasing + { + if (VERBOSE) { + System.out.println("TEST: now test UpToTwoPositiveIntOutputs"); + } + final UpToTwoPositiveIntOutputs outputs = UpToTwoPositiveIntOutputs.getSingleton(true); + final List> pairs = new ArrayList>(terms.length); + long lastOutput = 0; + for(int idx=0;idx(terms[idx], output)); + } + new FSTTester(random, dir, inputMode, pairs, outputs).doTest(); + } } private static class FSTTester { @@ -328,11 +358,13 @@ public class TestFSTs extends LuceneTestCase { // no pruning doTest(0, 0); - // simple pruning - doTest(_TestUtil.nextInt(random, 1, 1+pairs.size()), 0); - - // leafy pruning - doTest(0, _TestUtil.nextInt(random, 1, 1+pairs.size())); + if (!(outputs instanceof UpToTwoPositiveIntOutputs)) { + // simple pruning + doTest(_TestUtil.nextInt(random, 1, 1+pairs.size()), 0); + + // leafy pruning + doTest(0, _TestUtil.nextInt(random, 1, 1+pairs.size())); + } } // runs the term, returning the output, or null if term @@ -421,7 +453,14 @@ public class TestFSTs extends LuceneTestCase { prune1==0 && prune2==0, outputs); for(InputOutput pair : pairs) { - builder.add(pair.input, pair.output); + if (pair.output instanceof UpToTwoPositiveIntOutputs.TwoLongs) { + final UpToTwoPositiveIntOutputs _outputs = (UpToTwoPositiveIntOutputs) outputs; + final UpToTwoPositiveIntOutputs.TwoLongs twoLongs = (UpToTwoPositiveIntOutputs.TwoLongs) pair.output; + ((Builder) builder).add(pair.input, (Object) _outputs.get(twoLongs.first)); + ((Builder) builder).add(pair.input, (Object) _outputs.get(twoLongs.second)); + } else { + builder.add(pair.input, pair.output); + } } FST fst = builder.finish(); From 3a9eae5a28913a14d9aae5c9fe523ad24b8d670d Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Thu, 12 May 2011 21:51:19 +0000 Subject: [PATCH 57/57] LUCENE-2984: Move hasVectors() & hasProx() responsibility out of SegmentInfo to FieldInfos git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1102476 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/index/DocFieldProcessor.java | 7 +- .../index/DocumentsWriterPerThread.java | 13 +-- .../org/apache/lucene/index/FieldInfo.java | 25 ++++- .../org/apache/lucene/index/FieldInfos.java | 49 ++++++++- .../apache/lucene/index/IndexFileDeleter.java | 27 ++++- .../org/apache/lucene/index/IndexWriter.java | 31 +++--- .../org/apache/lucene/index/SegmentInfo.java | 73 +++++++------ .../apache/lucene/index/SegmentMerger.java | 4 +- .../lucene/index/SegmentWriteState.java | 1 - .../lucene/index/TermVectorsTermsWriter.java | 6 +- .../codecs/sep/SepPostingsReaderImpl.java | 2 +- .../mockintblock/MockFixedIntBlockCodec.java | 2 +- .../MockVariableIntBlockCodec.java | 2 +- .../index/codecs/mocksep/MockSepCodec.java | 2 +- .../org/apache/lucene/index/TestCodecs.java | 5 +- .../test/org/apache/lucene/index/TestDoc.java | 5 +- .../index/TestIndexWriterExceptions.java | 103 +++++++++++++++++- .../lucene/index/TestSegmentMerger.java | 6 +- 18 files changed, 275 insertions(+), 88 deletions(-) diff --git a/lucene/src/java/org/apache/lucene/index/DocFieldProcessor.java b/lucene/src/java/org/apache/lucene/index/DocFieldProcessor.java index c7f022e4747..e3e9f234220 100644 --- a/lucene/src/java/org/apache/lucene/index/DocFieldProcessor.java +++ b/lucene/src/java/org/apache/lucene/index/DocFieldProcessor.java @@ -235,9 +235,10 @@ final class DocFieldProcessor extends DocConsumer { // enabled; we could save [small amount of] CPU // here. ArrayUtil.quickSort(fields, 0, fieldCount, fieldsComp); - - for(int i=0;i { static final byte OMIT_TERM_FREQ_AND_POSITIONS = 0x40; private int format; + private boolean hasProx; // only set if readonly + private boolean hasVectors; // only set if readonly + private long version; // internal use to track changes + /** * Creates a new {@link FieldInfos} instance with a private @@ -263,7 +267,7 @@ public final class FieldInfos implements Iterable { */ public FieldInfos(Directory d, String name) throws IOException { this((FieldNumberBiMap)null, null); // use null here to make this FIs Read-Only - IndexInput input = d.openInput(name); + final IndexInput input = d.openInput(name); try { read(input, name); } finally { @@ -299,6 +303,9 @@ public final class FieldInfos implements Iterable { @Override synchronized public Object clone() { FieldInfos fis = new FieldInfos(globalFieldNumbers, segmentCodecsBuilder); + fis.format = format; + fis.hasProx = hasProx; + fis.hasVectors = hasVectors; for (FieldInfo fi : this) { FieldInfo clone = (FieldInfo) (fi).clone(); fis.putInternal(clone); @@ -308,6 +315,10 @@ public final class FieldInfos implements Iterable { /** Returns true if any fields do not omitTermFreqAndPositions */ public boolean hasProx() { + if (isReadOnly()) { + return hasProx; + } + // mutable FIs must check! for (FieldInfo fi : this) { if (fi.isIndexed && !fi.omitTermFreqAndPositions) { return true; @@ -440,6 +451,7 @@ public final class FieldInfos implements Iterable { if (fi.isIndexed && fi.getCodecId() == FieldInfo.UNASSIGNED_CODEC_ID) { segmentCodecsBuilder.tryAddAndSet(fi); } + version++; return fi; } @@ -510,6 +522,10 @@ public final class FieldInfos implements Iterable { } public boolean hasVectors() { + if (isReadOnly()) { + return hasVectors; + } + // mutable FIs must check for (FieldInfo fi : this) { if (fi.storeTermVector) { return true; @@ -562,6 +578,10 @@ public final class FieldInfos implements Iterable { public final boolean isReadOnly() { return globalFieldNumbers == null; } + + synchronized final long getVersion() { + return version; + } public void write(IndexOutput output) throws IOException { output.writeVInt(FORMAT_CURRENT); @@ -615,7 +635,8 @@ public final class FieldInfos implements Iterable { if (omitTermFreqAndPositions) { storePayloads = false; } - + hasVectors |= storeTermVector; + hasProx |= isIndexed && !omitTermFreqAndPositions; final FieldInfo addInternal = addInternal(name, fieldNumber, isIndexed, storeTermVector, storePositionsWithTermVector, storeOffsetWithTermVector, omitNorms, storePayloads, omitTermFreqAndPositions); addInternal.setCodecId(codecId); } @@ -624,5 +645,29 @@ public final class FieldInfos implements Iterable { throw new CorruptIndexException("did not read all bytes from file \"" + fileName + "\": read " + input.getFilePointer() + " vs size " + input.length()); } } + + /** + * Reverts all uncommitted changes + * @see FieldInfo#revertUncommitted() + */ + void revertUncommitted() { + for (FieldInfo fieldInfo : this) { + fieldInfo.revertUncommitted(); + } + } + + final FieldInfos asReadOnly() { + if (isReadOnly()) { + return this; + } + final FieldInfos roFis = new FieldInfos((FieldNumberBiMap)null, null); + for (FieldInfo fieldInfo : this) { + FieldInfo clone = (FieldInfo) (fieldInfo).clone(); + roFis.putInternal(clone); + roFis.hasVectors |= clone.storeTermVector; + roFis.hasProx |= clone.isIndexed && !clone.omitTermFreqAndPositions; + } + return roFis; + } } diff --git a/lucene/src/java/org/apache/lucene/index/IndexFileDeleter.java b/lucene/src/java/org/apache/lucene/index/IndexFileDeleter.java index ecf41bacabc..c4559870cfb 100644 --- a/lucene/src/java/org/apache/lucene/index/IndexFileDeleter.java +++ b/lucene/src/java/org/apache/lucene/index/IndexFileDeleter.java @@ -22,6 +22,7 @@ import java.io.FilenameFilter; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -196,7 +197,31 @@ final class IndexFileDeleter { } } if (sis != null) { - CommitPoint commitPoint = new CommitPoint(commitsToDelete, directory, sis); + final SegmentInfos infos = sis; + for (SegmentInfo segmentInfo : infos) { + try { + /* + * Force FI to load for each segment since we could see a + * segments file and load successfully above if the files are + * still referenced when they are deleted and the os doesn't let + * you delete them. Yet its likely that fnm files are removed + * while seg file is still around Since LUCENE-2984 we need FI + * to find out if a seg has vectors and prox so we need those + * files to be opened for a commit point. + */ + segmentInfo.getFieldInfos(); + } catch (FileNotFoundException e) { + refresh(segmentInfo.name); + sis = null; + if (infoStream != null) { + message("init: hit FileNotFoundException when loading commit \"" + fileName + "\"; skipping this commit point"); + } + } + } + + } + if (sis != null) { + final CommitPoint commitPoint = new CommitPoint(commitsToDelete, directory, sis); if (sis.getGeneration() == segmentInfos.getGeneration()) { currentCommitPoint = commitPoint; } diff --git a/lucene/src/java/org/apache/lucene/index/IndexWriter.java b/lucene/src/java/org/apache/lucene/index/IndexWriter.java index 4d924627828..2a6d4ae9519 100644 --- a/lucene/src/java/org/apache/lucene/index/IndexWriter.java +++ b/lucene/src/java/org/apache/lucene/index/IndexWriter.java @@ -2355,7 +2355,7 @@ public class IndexWriter implements Closeable { String mergedName = newSegmentName(); SegmentMerger merger = new SegmentMerger(directory, config.getTermIndexInterval(), - mergedName, null, codecs, payloadProcessorProvider, + mergedName, null, payloadProcessorProvider, globalFieldNumberMap.newFieldInfos(SegmentCodecsBuilder.create(codecs))); for (IndexReader reader : readers) // add new indexes @@ -2365,8 +2365,7 @@ public class IndexWriter implements Closeable { final FieldInfos fieldInfos = merger.fieldInfos(); SegmentInfo info = new SegmentInfo(mergedName, docCount, directory, - false, fieldInfos.hasProx(), merger.getSegmentCodecs(), - fieldInfos.hasVectors(), + false, merger.getSegmentCodecs(), fieldInfos); setDiagnostics(info, "addIndexes(IndexReader...)"); @@ -3041,7 +3040,16 @@ public class IndexWriter implements Closeable { // is running (while synchronized) to avoid race // condition where two conflicting merges from different // threads, start - message("registerMerge merging=" + mergingSegments); + if (infoStream != null) { + StringBuilder builder = new StringBuilder("registerMerge merging= ["); + for (SegmentInfo info : mergingSegments) { + builder.append(info.name).append(", "); + } + builder.append("]"); + // don't call mergingSegments.toString() could lead to ConcurrentModException + // since merge updates the segments FieldInfos + message(builder.toString()); + } for(SegmentInfo info : merge.segments) { message("registerMerge info=" + info); mergingSegments.add(info); @@ -3094,7 +3102,7 @@ public class IndexWriter implements Closeable { // Bind a new segment name here so even with // ConcurrentMergePolicy we keep deterministic segment // names. - merge.info = new SegmentInfo(newSegmentName(), 0, directory, false, false, null, false, globalFieldNumberMap.newFieldInfos(SegmentCodecsBuilder.create(codecs))); + merge.info = new SegmentInfo(newSegmentName(), 0, directory, false, null, globalFieldNumberMap.newFieldInfos(SegmentCodecsBuilder.create(codecs))); // Lock order: IW -> BD final BufferedDeletesStream.ApplyDeletesResult result = bufferedDeletesStream.applyDeletes(readerPool, merge.segments); @@ -3258,16 +3266,14 @@ public class IndexWriter implements Closeable { List sourceSegments = merge.segments; SegmentMerger merger = new SegmentMerger(directory, config.getTermIndexInterval(), mergedName, merge, - codecs, payloadProcessorProvider, - merge.info.getFieldInfos()); + payloadProcessorProvider, merge.info.getFieldInfos()); if (infoStream != null) { - message("merging " + merge.segString(directory) + " mergeVectors=" + merger.fieldInfos().hasVectors()); + message("merging " + merge.segString(directory) + " mergeVectors=" + merge.info.getFieldInfos().hasVectors()); } merge.readers = new ArrayList(); merge.readerClones = new ArrayList(); - // This is try/finally to make sure merger's readers are // closed: boolean success = false; @@ -3309,8 +3315,6 @@ public class IndexWriter implements Closeable { // Record which codec was used to write the segment merge.info.setSegmentCodecs(merger.getSegmentCodecs()); - // Record if we have merged vectors - merge.info.setHasVectors(merger.fieldInfos().hasVectors()); if (infoStream != null) { message("merge segmentCodecs=" + merger.getSegmentCodecs()); @@ -3324,13 +3328,11 @@ public class IndexWriter implements Closeable { // because codec must know if prox was written for // this segment: //System.out.println("merger set hasProx=" + merger.hasProx() + " seg=" + merge.info.name); - merge.info.setHasProx(merger.fieldInfos().hasProx()); - boolean useCompoundFile; synchronized (this) { // Guard segmentInfos useCompoundFile = mergePolicy.useCompoundFile(segmentInfos, merge.info); } - + if (useCompoundFile) { success = false; final String compoundFileName = IndexFileNames.segmentFileName(mergedName, "", IndexFileNames.COMPOUND_FILE_EXTENSION); @@ -3532,6 +3534,7 @@ public class IndexWriter implements Closeable { // called only from assert private boolean filesExist(SegmentInfos toSync) throws IOException { + Collection files = toSync.files(directory, false); for(final String fileName: files) { assert directory.fileExists(fileName): "file " + fileName + " does not exist"; diff --git a/lucene/src/java/org/apache/lucene/index/SegmentInfo.java b/lucene/src/java/org/apache/lucene/index/SegmentInfo.java index 3313a04e123..af33754e02a 100644 --- a/lucene/src/java/org/apache/lucene/index/SegmentInfo.java +++ b/lucene/src/java/org/apache/lucene/index/SegmentInfo.java @@ -41,7 +41,8 @@ import org.apache.lucene.util.Constants; * @lucene.experimental */ public final class SegmentInfo { - + // TODO: remove with hasVector and hasProx + private static final int CHECK_FIELDINFO = -2; static final int NO = -1; // e.g. no norms; no deletes; static final int YES = 1; // e.g. have norms; have deletes; static final int WITHOUT_GEN = 0; // a file name that has no GEN in it. @@ -83,10 +84,12 @@ public final class SegmentInfo { private boolean docStoreIsCompoundFile; // whether doc store files are stored in compound file (*.cfx) private int delCount; // How many deleted docs in this segment + + //TODO: remove when we don't have to support old indexes anymore that had this field + private int hasVectors = CHECK_FIELDINFO; + //TODO: remove when we don't have to support old indexes anymore that had this field + private int hasProx = CHECK_FIELDINFO; // True if this segment has any fields with omitTermFreqAndPositions==false - private boolean hasProx; // True if this segment has any fields with omitTermFreqAndPositions==false - - private boolean hasVectors; // True if this segment wrote term vectors private FieldInfos fieldInfos; @@ -104,9 +107,12 @@ public final class SegmentInfo { // NOTE: only used in-RAM by IW to track buffered deletes; // this is never written to/read from the Directory private long bufferedDeletesGen; - + + // holds the fieldInfos Version to refresh files() cache if FI has changed + private long fieldInfosVersion; + public SegmentInfo(String name, int docCount, Directory dir, boolean isCompoundFile, - boolean hasProx, SegmentCodecs segmentCodecs, boolean hasVectors, FieldInfos fieldInfos) { + SegmentCodecs segmentCodecs, FieldInfos fieldInfos) { this.name = name; this.docCount = docCount; this.dir = dir; @@ -114,9 +120,7 @@ public final class SegmentInfo { this.isCompoundFile = isCompoundFile; this.docStoreOffset = -1; this.docStoreSegment = name; - this.hasProx = hasProx; this.segmentCodecs = segmentCodecs; - this.hasVectors = hasVectors; delCount = 0; version = Constants.LUCENE_MAIN_VERSION; this.fieldInfos = fieldInfos; @@ -211,7 +215,7 @@ public final class SegmentInfo { delCount = input.readInt(); assert delCount <= docCount; - hasProx = input.readByte() == YES; + hasProx = input.readByte(); // System.out.println(Thread.currentThread().getName() + ": si.read hasProx=" + hasProx + " seg=" + name); if (format <= DefaultSegmentInfosWriter.FORMAT_4_0) { @@ -224,7 +228,7 @@ public final class SegmentInfo { diagnostics = input.readStringStringMap(); if (format <= DefaultSegmentInfosWriter.FORMAT_HAS_VECTORS) { - hasVectors = input.readByte() == 1; + hasVectors = input.readByte(); } else { final String storesSegment; final String ext; @@ -245,7 +249,7 @@ public final class SegmentInfo { dirToTest = dir; } try { - hasVectors = dirToTest.fileExists(IndexFileNames.segmentFileName(storesSegment, "", IndexFileNames.VECTORS_INDEX_EXTENSION)); + hasVectors = dirToTest.fileExists(IndexFileNames.segmentFileName(storesSegment, "", IndexFileNames.VECTORS_INDEX_EXTENSION)) ? YES : NO; } finally { if (isCompoundFile) { dirToTest.close(); @@ -309,14 +313,9 @@ public final class SegmentInfo { } public boolean getHasVectors() throws IOException { - return hasVectors; + return hasVectors == CHECK_FIELDINFO ? getFieldInfos().hasVectors() : hasVectors == YES; } - - public void setHasVectors(boolean v) { - hasVectors = v; - clearFilesCache(); - } - + public FieldInfos getFieldInfos() throws IOException { loadFieldInfos(dir, true); return fieldInfos; @@ -347,7 +346,7 @@ public final class SegmentInfo { @Override public Object clone() { - final SegmentInfo si = new SegmentInfo(name, docCount, dir, isCompoundFile, hasProx, segmentCodecs, hasVectors, + final SegmentInfo si = new SegmentInfo(name, docCount, dir, isCompoundFile, segmentCodecs, fieldInfos == null ? null : (FieldInfos) fieldInfos.clone()); si.docStoreOffset = docStoreOffset; si.docStoreSegment = docStoreSegment; @@ -362,6 +361,8 @@ public final class SegmentInfo { } } si.version = version; + si.hasProx = hasProx; + si.hasVectors = hasVectors; return si; } @@ -567,19 +568,14 @@ public final class SegmentInfo { output.writeByte((byte) (isCompoundFile ? YES : NO)); output.writeInt(delCount); - output.writeByte((byte) (hasProx ? 1:0)); + output.writeByte((byte) (hasProx)); segmentCodecs.write(output); output.writeStringStringMap(diagnostics); - output.writeByte((byte) (hasVectors ? 1 : 0)); + output.writeByte((byte) (hasVectors)); } - void setHasProx(boolean hasProx) { - this.hasProx = hasProx; - clearFilesCache(); - } - - public boolean getHasProx() { - return hasProx; + public boolean getHasProx() throws IOException { + return hasProx == CHECK_FIELDINFO ? getFieldInfos().hasProx() : hasProx == YES; } /** Can only be called once. */ @@ -607,13 +603,14 @@ public final class SegmentInfo { */ public List files() throws IOException { - - if (files != null) { + final long fisVersion = fieldInfosVersion; + if (fisVersion != (fieldInfosVersion = getFieldInfos().getVersion())) { + clearFilesCache(); // FIS has modifications - need to recompute + } else if (files != null) { // Already cached: return files; } - - Set fileSet = new HashSet(); + final Set fileSet = new HashSet(); boolean useCompoundFile = getUseCompoundFile(); @@ -635,7 +632,7 @@ public final class SegmentInfo { } else { fileSet.add(IndexFileNames.segmentFileName(docStoreSegment, "", IndexFileNames.FIELDS_INDEX_EXTENSION)); fileSet.add(IndexFileNames.segmentFileName(docStoreSegment, "", IndexFileNames.FIELDS_EXTENSION)); - if (hasVectors) { + if (getHasVectors()) { fileSet.add(IndexFileNames.segmentFileName(docStoreSegment, "", IndexFileNames.VECTORS_INDEX_EXTENSION)); fileSet.add(IndexFileNames.segmentFileName(docStoreSegment, "", IndexFileNames.VECTORS_DOCUMENTS_EXTENSION)); fileSet.add(IndexFileNames.segmentFileName(docStoreSegment, "", IndexFileNames.VECTORS_FIELDS_EXTENSION)); @@ -644,7 +641,7 @@ public final class SegmentInfo { } else if (!useCompoundFile) { fileSet.add(IndexFileNames.segmentFileName(name, "", IndexFileNames.FIELDS_INDEX_EXTENSION)); fileSet.add(IndexFileNames.segmentFileName(name, "", IndexFileNames.FIELDS_EXTENSION)); - if (hasVectors) { + if (getHasVectors()) { fileSet.add(IndexFileNames.segmentFileName(name, "", IndexFileNames.VECTORS_INDEX_EXTENSION)); fileSet.add(IndexFileNames.segmentFileName(name, "", IndexFileNames.VECTORS_DOCUMENTS_EXTENSION)); fileSet.add(IndexFileNames.segmentFileName(name, "", IndexFileNames.VECTORS_FIELDS_EXTENSION)); @@ -707,8 +704,12 @@ public final class SegmentInfo { if (this.dir != dir) { s.append('x'); } - if (hasVectors) { - s.append('v'); + try { + if (getHasVectors()) { + s.append('v'); + } + } catch (IOException e) { + throw new RuntimeException(e); } s.append(docCount); diff --git a/lucene/src/java/org/apache/lucene/index/SegmentMerger.java b/lucene/src/java/org/apache/lucene/index/SegmentMerger.java index 67e279b3c15..394f3cc501e 100644 --- a/lucene/src/java/org/apache/lucene/index/SegmentMerger.java +++ b/lucene/src/java/org/apache/lucene/index/SegmentMerger.java @@ -65,16 +65,14 @@ final class SegmentMerger { when merging stored fields */ private final static int MAX_RAW_MERGE_DOCS = 4192; - private final CodecProvider codecs; private Codec codec; private SegmentWriteState segmentWriteState; private PayloadProcessorProvider payloadProcessorProvider; - SegmentMerger(Directory dir, int termIndexInterval, String name, MergePolicy.OneMerge merge, CodecProvider codecs, PayloadProcessorProvider payloadProcessorProvider, FieldInfos fieldInfos) { + SegmentMerger(Directory dir, int termIndexInterval, String name, MergePolicy.OneMerge merge, PayloadProcessorProvider payloadProcessorProvider, FieldInfos fieldInfos) { this.payloadProcessorProvider = payloadProcessorProvider; directory = dir; - this.codecs = codecs; segment = name; this.fieldInfos = fieldInfos; if (merge != null) { diff --git a/lucene/src/java/org/apache/lucene/index/SegmentWriteState.java b/lucene/src/java/org/apache/lucene/index/SegmentWriteState.java index e44462cc72d..b769ed08852 100644 --- a/lucene/src/java/org/apache/lucene/index/SegmentWriteState.java +++ b/lucene/src/java/org/apache/lucene/index/SegmentWriteState.java @@ -31,7 +31,6 @@ public class SegmentWriteState { public final String segmentName; public final FieldInfos fieldInfos; public final int numDocs; - public boolean hasVectors; // Deletes to apply while we are flushing the segment. A // Term is enrolled in here if it was deleted at one diff --git a/lucene/src/java/org/apache/lucene/index/TermVectorsTermsWriter.java b/lucene/src/java/org/apache/lucene/index/TermVectorsTermsWriter.java index da43f3ad311..fa956dda190 100644 --- a/lucene/src/java/org/apache/lucene/index/TermVectorsTermsWriter.java +++ b/lucene/src/java/org/apache/lucene/index/TermVectorsTermsWriter.java @@ -63,7 +63,6 @@ final class TermVectorsTermsWriter extends TermsHashConsumer { } lastDocID = 0; - state.hasVectors = hasVectors; hasVectors = false; } @@ -121,8 +120,7 @@ final class TermVectorsTermsWriter extends TermsHashConsumer { fill(docState.docID); // Append term vectors to the real outputs: - long pointer = tvd.getFilePointer(); - tvx.writeLong(pointer); + tvx.writeLong(tvd.getFilePointer()); tvx.writeLong(tvf.getFilePointer()); tvd.writeVInt(numVectorFields); if (numVectorFields > 0) { @@ -136,6 +134,8 @@ final class TermVectorsTermsWriter extends TermsHashConsumer { tvd.writeVLong(pos-lastPos); lastPos = pos; perFields[i].finishDocument(); + // commit the termVectors once successful success - FI will otherwise reset them + perFields[i].fieldInfo.commitVectors(); } } diff --git a/lucene/src/java/org/apache/lucene/index/codecs/sep/SepPostingsReaderImpl.java b/lucene/src/java/org/apache/lucene/index/codecs/sep/SepPostingsReaderImpl.java index d6fda7627da..392cb08ad61 100644 --- a/lucene/src/java/org/apache/lucene/index/codecs/sep/SepPostingsReaderImpl.java +++ b/lucene/src/java/org/apache/lucene/index/codecs/sep/SepPostingsReaderImpl.java @@ -85,7 +85,7 @@ public class SepPostingsReaderImpl extends PostingsReaderBase { } } - public static void files(SegmentInfo segmentInfo, String codecId, Collection files) { + public static void files(SegmentInfo segmentInfo, String codecId, Collection files) throws IOException { files.add(IndexFileNames.segmentFileName(segmentInfo.name, codecId, SepPostingsWriterImpl.DOC_EXTENSION)); files.add(IndexFileNames.segmentFileName(segmentInfo.name, codecId, SepPostingsWriterImpl.SKIP_EXTENSION)); diff --git a/lucene/src/test-framework/org/apache/lucene/index/codecs/mockintblock/MockFixedIntBlockCodec.java b/lucene/src/test-framework/org/apache/lucene/index/codecs/mockintblock/MockFixedIntBlockCodec.java index b6534718b56..0fa3f9b6b5d 100644 --- a/lucene/src/test-framework/org/apache/lucene/index/codecs/mockintblock/MockFixedIntBlockCodec.java +++ b/lucene/src/test-framework/org/apache/lucene/index/codecs/mockintblock/MockFixedIntBlockCodec.java @@ -186,7 +186,7 @@ public class MockFixedIntBlockCodec extends Codec { } @Override - public void files(Directory dir, SegmentInfo segmentInfo, String codecId, Set files) { + public void files(Directory dir, SegmentInfo segmentInfo, String codecId, Set files) throws IOException { SepPostingsReaderImpl.files(segmentInfo, codecId, files); BlockTermsReader.files(dir, segmentInfo, codecId, files); FixedGapTermsIndexReader.files(dir, segmentInfo, codecId, files); diff --git a/lucene/src/test-framework/org/apache/lucene/index/codecs/mockintblock/MockVariableIntBlockCodec.java b/lucene/src/test-framework/org/apache/lucene/index/codecs/mockintblock/MockVariableIntBlockCodec.java index 63a6eb40308..2062c769526 100644 --- a/lucene/src/test-framework/org/apache/lucene/index/codecs/mockintblock/MockVariableIntBlockCodec.java +++ b/lucene/src/test-framework/org/apache/lucene/index/codecs/mockintblock/MockVariableIntBlockCodec.java @@ -211,7 +211,7 @@ public class MockVariableIntBlockCodec extends Codec { } @Override - public void files(Directory dir, SegmentInfo segmentInfo, String codecId, Set files) { + public void files(Directory dir, SegmentInfo segmentInfo, String codecId, Set files) throws IOException { SepPostingsReaderImpl.files(segmentInfo, codecId, files); BlockTermsReader.files(dir, segmentInfo, codecId, files); FixedGapTermsIndexReader.files(dir, segmentInfo, codecId, files); diff --git a/lucene/src/test-framework/org/apache/lucene/index/codecs/mocksep/MockSepCodec.java b/lucene/src/test-framework/org/apache/lucene/index/codecs/mocksep/MockSepCodec.java index 6a059d8a619..5afce68bf80 100644 --- a/lucene/src/test-framework/org/apache/lucene/index/codecs/mocksep/MockSepCodec.java +++ b/lucene/src/test-framework/org/apache/lucene/index/codecs/mocksep/MockSepCodec.java @@ -130,7 +130,7 @@ public class MockSepCodec extends Codec { } @Override - public void files(Directory dir, SegmentInfo segmentInfo, String codecId, Set files) { + public void files(Directory dir, SegmentInfo segmentInfo, String codecId, Set files) throws IOException { SepPostingsReaderImpl.files(segmentInfo, codecId, files); BlockTermsReader.files(dir, segmentInfo, codecId, files); FixedGapTermsIndexReader.files(dir, segmentInfo, codecId, files); diff --git a/lucene/src/test/org/apache/lucene/index/TestCodecs.java b/lucene/src/test/org/apache/lucene/index/TestCodecs.java index bae4eb46aea..118c25c68cd 100644 --- a/lucene/src/test/org/apache/lucene/index/TestCodecs.java +++ b/lucene/src/test/org/apache/lucene/index/TestCodecs.java @@ -240,8 +240,7 @@ public class TestCodecs extends LuceneTestCase { final Directory dir = newDirectory(); FieldInfos clonedFieldInfos = (FieldInfos) fieldInfos.clone(); this.write(fieldInfos, dir, fields, true); - final SegmentInfo si = new SegmentInfo(SEGMENT, 10000, dir, false, true, clonedFieldInfos.buildSegmentCodecs(false), clonedFieldInfos.hasVectors(), clonedFieldInfos); - si.setHasProx(false); + final SegmentInfo si = new SegmentInfo(SEGMENT, 10000, dir, false, clonedFieldInfos.buildSegmentCodecs(false), clonedFieldInfos); final FieldsProducer reader = si.getSegmentCodecs().codec().fieldsProducer(new SegmentReadState(dir, si, fieldInfos, 64, IndexReader.DEFAULT_TERMS_INDEX_DIVISOR)); @@ -293,7 +292,7 @@ public class TestCodecs extends LuceneTestCase { FieldInfos clonedFieldInfos = (FieldInfos) fieldInfos.clone(); this.write(fieldInfos, dir, fields, false); - final SegmentInfo si = new SegmentInfo(SEGMENT, 10000, dir, false, true, clonedFieldInfos.buildSegmentCodecs(false), clonedFieldInfos.hasVectors(), clonedFieldInfos); + final SegmentInfo si = new SegmentInfo(SEGMENT, 10000, dir, false, clonedFieldInfos.buildSegmentCodecs(false), clonedFieldInfos); if (VERBOSE) { System.out.println("TEST: now read postings"); diff --git a/lucene/src/test/org/apache/lucene/index/TestDoc.java b/lucene/src/test/org/apache/lucene/index/TestDoc.java index 874df62c91a..9352f9174c9 100644 --- a/lucene/src/test/org/apache/lucene/index/TestDoc.java +++ b/lucene/src/test/org/apache/lucene/index/TestDoc.java @@ -196,7 +196,7 @@ public class TestDoc extends LuceneTestCase { SegmentReader r1 = SegmentReader.get(true, si1, IndexReader.DEFAULT_TERMS_INDEX_DIVISOR); SegmentReader r2 = SegmentReader.get(true, si2, IndexReader.DEFAULT_TERMS_INDEX_DIVISOR); - SegmentMerger merger = new SegmentMerger(si1.dir, IndexWriterConfig.DEFAULT_TERM_INDEX_INTERVAL, merged, null, CodecProvider.getDefault(), null, new FieldInfos()); + SegmentMerger merger = new SegmentMerger(si1.dir, IndexWriterConfig.DEFAULT_TERM_INDEX_INTERVAL, merged, null, null, new FieldInfos()); merger.add(r1); merger.add(r2); @@ -205,8 +205,7 @@ public class TestDoc extends LuceneTestCase { r2.close(); final FieldInfos fieldInfos = merger.fieldInfos(); final SegmentInfo info = new SegmentInfo(merged, si1.docCount + si2.docCount, si1.dir, - false, fieldInfos.hasProx(), merger.getSegmentCodecs(), - fieldInfos.hasVectors(), fieldInfos); + false, merger.getSegmentCodecs(), fieldInfos); if (useCompoundFile) { Collection filesToDelete = merger.createCompoundFile(merged + ".cfs", info); diff --git a/lucene/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java b/lucene/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java index 4c3e6c98e15..bda5bc449e7 100644 --- a/lucene/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java +++ b/lucene/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java @@ -33,9 +33,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.store.Directory; import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexOutput; -import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.store.MockDirectoryWrapper; -import org.apache.lucene.store.MockDirectoryWrapper.Failure; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.MockAnalyzer; @@ -1179,4 +1177,105 @@ public class TestIndexWriterExceptions extends LuceneTestCase { writer.close(); dir.close(); } + + public void testTermVectorExceptions() throws IOException { + FailOnTermVectors[] failures = new FailOnTermVectors[] { + new FailOnTermVectors(FailOnTermVectors.AFTER_INIT_STAGE), + new FailOnTermVectors(FailOnTermVectors.INIT_STAGE), }; + for (int j = 0; j < 3 * RANDOM_MULTIPLIER; j++) { + for (FailOnTermVectors failure : failures) { + MockDirectoryWrapper dir = newDirectory(); + IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( + TEST_VERSION_CURRENT, new MockAnalyzer(random))); + dir.failOn(failure); + int numDocs = 10 + random.nextInt(30); + for (int i = 0; i < numDocs; i++) { + Document doc = new Document(); + Field field = newField(random, "field", "a field", Field.Store.YES, + Field.Index.ANALYZED); + doc.add(field); + // random TV + try { + w.addDocument(doc); + assertFalse(field.isTermVectorStored()); + } catch (RuntimeException e) { + assertTrue(e.getMessage().startsWith(FailOnTermVectors.EXC_MSG)); + } + if (random.nextInt(20) == 0) { + w.commit(); + _TestUtil.checkIndex(dir); + } + + } + Document document = new Document(); + document.add(new Field("field", "a field", Field.Store.YES, + Field.Index.ANALYZED)); + w.addDocument(document); + + for (int i = 0; i < numDocs; i++) { + Document doc = new Document(); + Field field = newField(random, "field", "a field", Field.Store.YES, + Field.Index.ANALYZED); + doc.add(field); + // random TV + try { + w.addDocument(doc); + assertFalse(field.isTermVectorStored()); + } catch (RuntimeException e) { + assertTrue(e.getMessage().startsWith(FailOnTermVectors.EXC_MSG)); + } + if (random.nextInt(20) == 0) { + w.commit(); + _TestUtil.checkIndex(dir); + } + } + document = new Document(); + document.add(new Field("field", "a field", Field.Store.YES, + Field.Index.ANALYZED)); + w.addDocument(document); + w.close(); + IndexReader reader = IndexReader.open(dir); + assertTrue(reader.numDocs() > 0); + reader.close(); + SegmentInfos sis = new SegmentInfos(); + sis.read(dir); + for (SegmentInfo segmentInfo : sis) { + assertFalse(segmentInfo.getHasVectors()); + } + dir.close(); + + } + } + } + + private static class FailOnTermVectors extends MockDirectoryWrapper.Failure { + + private static final String INIT_STAGE = "initTermVectorsWriter"; + private static final String AFTER_INIT_STAGE = "finishDocument"; + private static final String EXC_MSG = "FOTV"; + private final String stage; + + public FailOnTermVectors(String stage) { + this.stage = stage; + } + + @Override + public void eval(MockDirectoryWrapper dir) throws IOException { + StackTraceElement[] trace = new Exception().getStackTrace(); + boolean failOnInit = false; + boolean failOnfinish = false; + for (int i = 0; i < trace.length; i++) { + if ("org.apache.lucene.index.TermVectorsTermsWriter".equals(trace[i].getClassName()) && stage.equals(trace[i].getMethodName())) + failOnInit = true; + if ("org.apache.lucene.index.TermVectorsTermsWriter".equals(trace[i].getClassName()) && stage.equals(trace[i].getMethodName())) + failOnfinish = true; + } + + if (failOnInit) { + throw new RuntimeException(EXC_MSG + " fail on init"); + } else if (failOnfinish) { + throw new RuntimeException(EXC_MSG + " fail on finishDoc"); + } + } + } } diff --git a/lucene/src/test/org/apache/lucene/index/TestSegmentMerger.java b/lucene/src/test/org/apache/lucene/index/TestSegmentMerger.java index d161e130ccb..7961601c013 100644 --- a/lucene/src/test/org/apache/lucene/index/TestSegmentMerger.java +++ b/lucene/src/test/org/apache/lucene/index/TestSegmentMerger.java @@ -73,15 +73,15 @@ public class TestSegmentMerger extends LuceneTestCase { } public void testMerge() throws IOException { - SegmentMerger merger = new SegmentMerger(mergedDir, IndexWriterConfig.DEFAULT_TERM_INDEX_INTERVAL, mergedSegment, null, CodecProvider.getDefault(), null, new FieldInfos()); + SegmentMerger merger = new SegmentMerger(mergedDir, IndexWriterConfig.DEFAULT_TERM_INDEX_INTERVAL, mergedSegment, null, null, new FieldInfos()); merger.add(reader1); merger.add(reader2); int docsMerged = merger.merge(); assertTrue(docsMerged == 2); final FieldInfos fieldInfos = merger.fieldInfos(); //Should be able to open a new SegmentReader against the new directory - SegmentReader mergedReader = SegmentReader.get(false, mergedDir, new SegmentInfo(mergedSegment, docsMerged, mergedDir, false, fieldInfos.hasProx(), - merger.getSegmentCodecs(), fieldInfos.hasVectors(), fieldInfos), + SegmentReader mergedReader = SegmentReader.get(false, mergedDir, new SegmentInfo(mergedSegment, docsMerged, mergedDir, false, + merger.getSegmentCodecs(), fieldInfos), BufferedIndexInput.BUFFER_SIZE, true, IndexReader.DEFAULT_TERMS_INDEX_DIVISOR); assertTrue(mergedReader != null); assertTrue(mergedReader.numDocs() == 2);