Merged /lucene/dev/trunk:r1438171-1439161

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene4547@1439164 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Muir 2013-01-27 20:01:52 +00:00
commit a02bffb253
89 changed files with 1791 additions and 3641 deletions

View File

@ -58,6 +58,9 @@ Optimizations
* LUCENE-3298: FST can now be larger than 2.1 GB / 2.1 B nodes.
(James Dyer, Mike McCandless)
* LUCENE-4690: Performance improvements and non-hashing versions
of NumericUtils.*ToPrefixCoded() (yonik)
New Features
* LUCENE-4686: New specialized DGapVInt8IntEncoder for facets (now the
@ -70,9 +73,23 @@ New Features
compresses term vectors into chunks of documents similarly to
CompressingStoredFieldsFormat. (Adrien Grand)
* LUCENE-4695: Added LiveFieldValues utility class, for getting the
current (live, real-time) value for any indexed doc/field. The
class buffers recently indexed doc/field values until a new
near-real-time reader is opened that contains those changes.
(Robert Muir, Mike McCandless)
API Changes
* LUCENE-4709: FacetResultNode no longer has a residue field. (Shai Erera)
* LUCENE-4716: DrillDown.query now takes Occur, allowing to specify if
categories should be OR'ed or AND'ed. (Shai Erera)
* LUCENE-4695: ReferenceManager.RefreshListener.afterRefresh now takes
a boolean indicating whether a new reference was in fact opened, and
a new beforeRefresh method notifies you when a refresh attempt is
starting. (Robert Muir, Mike McCandless)
Bug Fixes
@ -414,6 +431,13 @@ Changes in Runtime Behavior
This only affects requests with depth>1. If you execute such requests and
rely on the facet results being returned flat (i.e. no hierarchy), you should
set the ResultMode to GLOBAL_FLAT. (Shai Erera, Gilad Barkai)
* LUCENE-1822: Improves the text window selection by recalculating the starting margin
once all phrases in the fragment have been identified in FastVectorHighlighter. This
way if a single word is matched in a fragment, it will appear in the middle of the highlight,
instead of 6 characters from the beginning. This way one can also guarantee that
the entirety of short texts are represented in a fragment by specifying a large
enough fragCharSize.
Optimizations

View File

@ -45,7 +45,7 @@ public abstract class CompressionMode {
@Override
public Compressor newCompressor() {
return LZ4_FAST_COMPRESSOR;
return new LZ4FastCompressor();
}
@Override
@ -95,7 +95,7 @@ public abstract class CompressionMode {
@Override
public Compressor newCompressor() {
return LZ4_HIGH_COMPRESSOR;
return new LZ4HighCompressor();
}
@Override
@ -147,25 +147,37 @@ public abstract class CompressionMode {
};
private static final Compressor LZ4_FAST_COMPRESSOR = new Compressor() {
private static final class LZ4FastCompressor extends Compressor {
private final LZ4.HashTable ht;
LZ4FastCompressor() {
ht = new LZ4.HashTable();
}
@Override
public void compress(byte[] bytes, int off, int len, DataOutput out)
throws IOException {
LZ4.compress(bytes, off, len, out);
LZ4.compress(bytes, off, len, out, ht);
}
};
}
private static final Compressor LZ4_HIGH_COMPRESSOR = new Compressor() {
private static final class LZ4HighCompressor extends Compressor {
private final LZ4.HCHashTable ht;
LZ4HighCompressor() {
ht = new LZ4.HCHashTable();
}
@Override
public void compress(byte[] bytes, int off, int len, DataOutput out)
throws IOException {
LZ4.compressHC(bytes, off, len, out);
LZ4.compressHC(bytes, off, len, out, ht);
}
};
}
private static final class DeflateDecompressor extends Decompressor {

View File

@ -30,7 +30,7 @@ import org.apache.lucene.util.packed.PackedInts;
* http://code.google.com/p/lz4/
* http://fastcompression.blogspot.fr/p/lz4.html
*/
class LZ4 {
final class LZ4 {
private LZ4() {}
@ -181,11 +181,29 @@ class LZ4 {
}
}
static final class HashTable {
private int hashLog;
private PackedInts.Mutable hashTable;
void reset(int len) {
final int bitsPerOffset = PackedInts.bitsRequired(len - LAST_LITERALS);
final int bitsPerOffsetLog = 32 - Integer.numberOfLeadingZeros(bitsPerOffset - 1);
hashLog = MEMORY_USAGE + 3 - bitsPerOffsetLog;
if (hashTable == null || hashTable.size() < 1 << hashLog || hashTable.getBitsPerValue() < bitsPerOffset) {
hashTable = PackedInts.getMutable(1 << hashLog, bitsPerOffset, PackedInts.DEFAULT);
} else {
hashTable.clear();
}
}
}
/**
* Compress <code>bytes[off:off+len]</code> into <code>out</code> using
* at most 16KB of memory.
* at most 16KB of memory. <code>ht</code> shouldn't be shared across threads
* but can safely be reused.
*/
public static void compress(byte[] bytes, int off, int len, DataOutput out) throws IOException {
public static void compress(byte[] bytes, int off, int len, DataOutput out, HashTable ht) throws IOException {
final int base = off;
final int end = off + len;
@ -196,11 +214,9 @@ class LZ4 {
final int limit = end - LAST_LITERALS;
final int matchLimit = limit - MIN_MATCH;
final int bitsPerOffset = PackedInts.bitsRequired(len - LAST_LITERALS);
final int bitsPerOffsetLog = 32 - Integer.numberOfLeadingZeros(bitsPerOffset - 1);
final int hashLog = MEMORY_USAGE + 3 - bitsPerOffsetLog;
final PackedInts.Mutable hashTable = PackedInts.getMutable(1 << hashLog, bitsPerOffset, PackedInts.DEFAULT);
ht.reset(len);
final int hashLog = ht.hashLog;
final PackedInts.Mutable hashTable = ht.hashTable;
main:
while (off < limit) {
@ -256,20 +272,24 @@ class LZ4 {
m2.ref = m1.ref;
}
private static class HashTable {
static final class HCHashTable {
static final int MAX_ATTEMPTS = 256;
static final int MASK = MAX_DISTANCE - 1;
int nextToUpdate;
private final int base;
private int base;
private final int[] hashTable;
private final short[] chainTable;
HashTable(int base) {
HCHashTable() {
hashTable = new int[HASH_TABLE_SIZE_HC];
chainTable = new short[MAX_DISTANCE];
}
private void reset(int base) {
this.base = base;
nextToUpdate = base;
hashTable = new int[HASH_TABLE_SIZE_HC];
Arrays.fill(hashTable, -1);
chainTable = new short[MAX_DISTANCE];
Arrays.fill(chainTable, (short) 0);
}
private int hashPointer(byte[] bytes, int off) {
@ -355,12 +375,14 @@ class LZ4 {
/**
* Compress <code>bytes[off:off+len]</code> into <code>out</code>. Compared to
* {@link LZ4#compress(byte[], int, int, DataOutput)}, this method is slower,
* uses more memory (~ 256KB), but should provide better compression ratios
* (especially on large inputs) because it chooses the best match among up to
* 256 candidates and then performs trade-offs to fix overlapping matches.
* {@link LZ4#compress(byte[], int, int, DataOutput, HashTable)}, this method
* is slower and uses more memory (~ 256KB per thread) but should provide
* better compression ratios (especially on large inputs) because it chooses
* the best match among up to 256 candidates and then performs trade-offs to
* fix overlapping matches. <code>ht</code> shouldn't be shared across threads
* but can safely be reused.
*/
public static void compressHC(byte[] src, int srcOff, int srcLen, DataOutput out) throws IOException {
public static void compressHC(byte[] src, int srcOff, int srcLen, DataOutput out, HCHashTable ht) throws IOException {
final int srcEnd = srcOff + srcLen;
final int matchLimit = srcEnd - LAST_LITERALS;
@ -368,7 +390,7 @@ class LZ4 {
int sOff = srcOff;
int anchor = sOff++;
final HashTable ht = new HashTable(srcOff);
ht.reset(srcOff);
final Match match0 = new Match();
final Match match1 = new Match();
final Match match2 = new Match();

View File

@ -0,0 +1,133 @@
package org.apache.lucene.search;
/*
* 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.Closeable;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** Tracks live field values across NRT reader reopens.
* This holds a map for all updated ids since
* the last reader reopen. Once the NRT reader is reopened,
* it prunes the map. This means you must reopen your NRT
* reader periodically otherwise the RAM consumption of
* this class will grow unbounded!
*
* <p>NOTE: you must ensure the same id is never updated at
* the same time by two threads, because in this case you
* cannot in general know which thread "won". */
public abstract class LiveFieldValues<T> implements ReferenceManager.RefreshListener, Closeable {
private volatile Map<String,T> current = new ConcurrentHashMap<String,T>();
private volatile Map<String,T> old = new ConcurrentHashMap<String,T>();
private final ReferenceManager<IndexSearcher> mgr;
private final T missingValue;
public LiveFieldValues(ReferenceManager<IndexSearcher> mgr, T missingValue) {
this.missingValue = missingValue;
this.mgr = mgr;
mgr.addListener(this);
}
@Override
public void close() {
mgr.removeListener(this);
}
@Override
public void beforeRefresh() throws IOException {
old = current;
// Start sending all updates after this point to the new
// map. While reopen is running, any lookup will first
// try this new map, then fallback to old, then to the
// current searcher:
current = new ConcurrentHashMap<String,T>();
}
@Override
public void afterRefresh(boolean didRefresh) throws IOException {
// Now drop all the old values because they are now
// visible via the searcher that was just opened; if
// didRefresh is false, it's possible old has some
// entries in it, which is fine: it means they were
// actually already included in the previously opened
// reader. So we can safely clear old here:
old = new ConcurrentHashMap<String,T>();
}
/** Call this after you've successfully added a document
* to the index, to record what value you just set the
* field to. */
public void add(String id, T value) {
current.put(id, value);
}
/** Call this after you've successfully deleted a document
* from the index. */
public void delete(String id) {
current.put(id, missingValue);
}
/** Returns the [approximate] number of id/value pairs
* buffered in RAM. */
public int size() {
return current.size() + old.size();
}
/** Returns the current value for this id, or null if the
* id isn't in the index or was deleted. */
public T get(String id) throws IOException {
// First try to get the "live" value:
T value = current.get(id);
if (value == missingValue) {
// Deleted but the deletion is not yet reflected in
// the reader:
return null;
} else if (value != null) {
return value;
} else {
value = old.get(id);
if (value == missingValue) {
// Deleted but the deletion is not yet reflected in
// the reader:
return null;
} else if (value != null) {
return value;
} else {
// It either does not exist in the index, or, it was
// already flushed & NRT reader was opened on the
// segment, so fallback to current searcher:
IndexSearcher s = mgr.acquire();
try {
return lookupFromSearcher(s, id);
} finally {
mgr.release(s);
}
}
}
}
/** This is called when the id/value was already flushed & opened
* in an NRT IndexSearcher. You must implement this to
* go look up the value (eg, via doc values, field cache,
* stored fields, etc.). */
protected abstract T lookupFromSearcher(IndexSearcher s, String id) throws IOException;
}

View File

@ -151,6 +151,7 @@ public abstract class ReferenceManager<G> implements Closeable {
try {
final G reference = acquire();
try {
notifyRefreshListenersBefore();
G newReference = refreshIfNeeded(reference);
if (newReference != null) {
assert newReference != reference : "refreshIfNeeded should return null if refresh wasn't needed";
@ -165,11 +166,9 @@ public abstract class ReferenceManager<G> implements Closeable {
}
} finally {
release(reference);
notifyRefreshListenersRefreshed(refreshed);
}
afterMaybeRefresh();
if (refreshed) {
notifyRefreshListeners();
}
} finally {
refreshLock.unlock();
}
@ -254,9 +253,15 @@ public abstract class ReferenceManager<G> implements Closeable {
decRef(reference);
}
private void notifyRefreshListeners() {
private void notifyRefreshListenersBefore() throws IOException {
for (RefreshListener refreshListener : refreshListeners) {
refreshListener.afterRefresh();
refreshListener.beforeRefresh();
}
}
private void notifyRefreshListenersRefreshed(boolean didRefresh) throws IOException {
for (RefreshListener refreshListener : refreshListeners) {
refreshListener.afterRefresh(didRefresh);
}
}
@ -284,9 +289,13 @@ public abstract class ReferenceManager<G> implements Closeable {
* finished. See {@link #addListener}. */
public interface RefreshListener {
/**
* Called after a successful refresh and a new reference has been installed. When this is called {@link #acquire()} is guaranteed to return a new instance.
*/
void afterRefresh();
/** Called right before a refresh attempt starts. */
void beforeRefresh() throws IOException;
/** Called after the attempted refresh; if the refresh
* did open a new reference then didRefresh will be true
* and {@link #acquire()} is guaranteed to return the new
* reference. */
void afterRefresh(boolean didRefresh) throws IOException;
}
}

View File

@ -82,7 +82,7 @@ public final class NumericUtils {
/**
* The maximum term length (used for <code>byte[]</code> buffer size)
* for encoding <code>long</code> values.
* @see #longToPrefixCoded(long,int,BytesRef)
* @see #longToPrefixCodedBytes
*/
public static final int BUF_SIZE_LONG = 63/7 + 2;
@ -95,7 +95,7 @@ public final class NumericUtils {
/**
* The maximum term length (used for <code>byte[]</code> buffer size)
* for encoding <code>int</code> values.
* @see #intToPrefixCoded(int,int,BytesRef)
* @see #intToPrefixCodedBytes
*/
public static final int BUF_SIZE_INT = 31/7 + 2;
@ -109,15 +109,42 @@ public final class NumericUtils {
* @return the hash code for indexing (TermsHash)
*/
public static int longToPrefixCoded(final long val, final int shift, final BytesRef bytes) {
if (shift>63 || shift<0)
longToPrefixCodedBytes(val, shift, bytes);
return bytes.hashCode();
}
/**
* Returns prefix coded bits after reducing the precision by <code>shift</code> bits.
* This is method is used by {@link NumericTokenStream}.
* After encoding, {@code bytes.offset} will always be 0.
* @param val the numeric value
* @param shift how many bits to strip from the right
* @param bytes will contain the encoded value
* @return the hash code for indexing (TermsHash)
*/
public static int intToPrefixCoded(final int val, final int shift, final BytesRef bytes) {
intToPrefixCodedBytes(val, shift, bytes);
return bytes.hashCode();
}
/**
* Returns prefix coded bits after reducing the precision by <code>shift</code> bits.
* This is method is used by {@link NumericTokenStream}.
* After encoding, {@code bytes.offset} will always be 0.
* @param val the numeric value
* @param shift how many bits to strip from the right
* @param bytes will contain the encoded value
*/
public static void longToPrefixCodedBytes(final long val, final int shift, final BytesRef bytes) {
if ((shift & ~0x3f) != 0) // ensure shift is 0..63
throw new IllegalArgumentException("Illegal shift value, must be 0..63");
int hash, nChars = (63-shift)/7 + 1;
int nChars = (((63-shift)*37)>>8) + 1; // i/7 is the same as (i*37)>>8 for i in 0..63
bytes.offset = 0;
bytes.length = nChars+1;
bytes.length = nChars+1; // one extra for the byte that contains the shift info
if (bytes.bytes.length < bytes.length) {
bytes.grow(NumericUtils.BUF_SIZE_LONG);
bytes.bytes = new byte[NumericUtils.BUF_SIZE_LONG]; // use the max
}
bytes.bytes[0] = (byte) (hash = (SHIFT_START_LONG + shift));
bytes.bytes[0] = (byte)(SHIFT_START_LONG + shift);
long sortableBits = val ^ 0x8000000000000000L;
sortableBits >>>= shift;
while (nChars > 0) {
@ -126,13 +153,9 @@ public final class NumericUtils {
bytes.bytes[nChars--] = (byte)(sortableBits & 0x7f);
sortableBits >>>= 7;
}
// calculate hash
for (int i = 1; i < bytes.length; i++) {
hash = 31*hash + bytes.bytes[i];
}
return hash;
}
/**
* Returns prefix coded bits after reducing the precision by <code>shift</code> bits.
* This is method is used by {@link NumericTokenStream}.
@ -140,18 +163,17 @@ public final class NumericUtils {
* @param val the numeric value
* @param shift how many bits to strip from the right
* @param bytes will contain the encoded value
* @return the hash code for indexing (TermsHash)
*/
public static int intToPrefixCoded(final int val, final int shift, final BytesRef bytes) {
if (shift>31 || shift<0)
public static void intToPrefixCodedBytes(final int val, final int shift, final BytesRef bytes) {
if ((shift & ~0x1f) != 0) // ensure shift is 0..31
throw new IllegalArgumentException("Illegal shift value, must be 0..31");
int hash, nChars = (31-shift)/7 + 1;
int nChars = (((31-shift)*37)>>8) + 1; // i/7 is the same as (i*37)>>8 for i in 0..63
bytes.offset = 0;
bytes.length = nChars+1;
bytes.length = nChars+1; // one extra for the byte that contains the shift info
if (bytes.bytes.length < bytes.length) {
bytes.grow(NumericUtils.BUF_SIZE_INT);
bytes.bytes = new byte[NumericUtils.BUF_SIZE_LONG]; // use the max
}
bytes.bytes[0] = (byte) (hash = (SHIFT_START_INT + shift));
bytes.bytes[0] = (byte)(SHIFT_START_INT + shift);
int sortableBits = val ^ 0x80000000;
sortableBits >>>= shift;
while (nChars > 0) {
@ -160,13 +182,9 @@ public final class NumericUtils {
bytes.bytes[nChars--] = (byte)(sortableBits & 0x7f);
sortableBits >>>= 7;
}
// calculate hash
for (int i = 1; i < bytes.length; i++) {
hash = 31*hash + bytes.bytes[i];
}
return hash;
}
/**
* Returns the shift value from a prefix encoded {@code long}.
* @throws NumberFormatException if the supplied {@link BytesRef} is
@ -197,7 +215,7 @@ public final class NumericUtils {
* This method can be used to decode a term's value.
* @throws NumberFormatException if the supplied {@link BytesRef} is
* not correctly prefix encoded.
* @see #longToPrefixCoded(long,int,BytesRef)
* @see #longToPrefixCodedBytes
*/
public static long prefixCodedToLong(final BytesRef val) {
long sortableBits = 0L;
@ -221,7 +239,7 @@ public final class NumericUtils {
* This method can be used to decode a term's value.
* @throws NumberFormatException if the supplied {@link BytesRef} is
* not correctly prefix encoded.
* @see #intToPrefixCoded(int,int,BytesRef)
* @see #intToPrefixCodedBytes
*/
public static int prefixCodedToInt(final BytesRef val) {
int sortableBits = 0;
@ -402,8 +420,8 @@ public final class NumericUtils {
*/
public void addRange(final long min, final long max, final int shift) {
final BytesRef minBytes = new BytesRef(BUF_SIZE_LONG), maxBytes = new BytesRef(BUF_SIZE_LONG);
longToPrefixCoded(min, shift, minBytes);
longToPrefixCoded(max, shift, maxBytes);
longToPrefixCodedBytes(min, shift, minBytes);
longToPrefixCodedBytes(max, shift, maxBytes);
addRange(minBytes, maxBytes);
}
@ -431,8 +449,8 @@ public final class NumericUtils {
*/
public void addRange(final int min, final int max, final int shift) {
final BytesRef minBytes = new BytesRef(BUF_SIZE_INT), maxBytes = new BytesRef(BUF_SIZE_INT);
intToPrefixCoded(min, shift, minBytes);
intToPrefixCoded(max, shift, maxBytes);
intToPrefixCodedBytes(min, shift, minBytes);
intToPrefixCodedBytes(max, shift, maxBytes);
addRange(minBytes, maxBytes);
}

View File

@ -0,0 +1,180 @@
package org.apache.lucene.search;
/*
* 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.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.index.StoredDocument;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.NRTManager.TrackingIndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util._TestUtil;
public class TestLiveFieldValues extends LuceneTestCase {
public void test() throws Exception {
Directory dir = newFSDirectory(_TestUtil.getTempDir("livefieldupdates"));
IndexWriterConfig iwc = newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random()));
final IndexWriter _w = new IndexWriter(dir, iwc);
final TrackingIndexWriter w = new TrackingIndexWriter(_w);
final NRTManager mgr = new NRTManager(w, new SearcherFactory() {
@Override
public IndexSearcher newSearcher(IndexReader r) {
return new IndexSearcher(r);
}
});
final Integer missing = -1;
final LiveFieldValues<Integer> rt = new LiveFieldValues<Integer>(mgr, missing) {
@Override
protected Integer lookupFromSearcher(IndexSearcher s, String id) throws IOException {
TermQuery tq = new TermQuery(new Term("id", id));
TopDocs hits = s.search(tq, 1);
assertTrue(hits.totalHits <= 1);
if (hits.totalHits == 0) {
return null;
} else {
StoredDocument doc = s.doc(hits.scoreDocs[0].doc);
return (Integer) doc.getField("field").numericValue();
}
}
};
int numThreads = _TestUtil.nextInt(random(), 2, 5);
if (VERBOSE) {
System.out.println(numThreads + " threads");
}
final CountDownLatch startingGun = new CountDownLatch(1);
List<Thread> threads = new ArrayList<Thread>();
final int iters = atLeast(1000);
final int idCount = _TestUtil.nextInt(random(), 100, 10000);
final double reopenChance = random().nextDouble()*0.01;
final double deleteChance = random().nextDouble()*0.25;
final double addChance = random().nextDouble()*0.5;
for(int t=0;t<numThreads;t++) {
final int threadID = t;
final Random threadRandom = new Random(random().nextLong());
Thread thread = new Thread() {
@Override
public void run() {
try {
Map<String,Integer> values = new HashMap<String,Integer>();
List<String> allIDs = Collections.synchronizedList(new ArrayList<String>());
startingGun.await();
for(int iter=0; iter<iters;iter++) {
// Add/update a document
Document doc = new Document();
// Threads must not update the same id at the
// same time:
if (threadRandom.nextDouble() <= addChance) {
String id = String.format(Locale.ROOT, "%d_%04x", threadID, threadRandom.nextInt(idCount));
Integer field = threadRandom.nextInt(Integer.MAX_VALUE);
doc.add(new StringField("id", id, Field.Store.YES));
doc.add(new IntField("field", field.intValue(), Field.Store.YES));
w.updateDocument(new Term("id", id), doc);
rt.add(id, field);
if (values.put(id, field) == null) {
allIDs.add(id);
}
}
if (allIDs.size() > 0 && threadRandom.nextDouble() <= deleteChance) {
String randomID = allIDs.get(threadRandom.nextInt(allIDs.size()));
w.deleteDocuments(new Term("id", randomID));
rt.delete(randomID);
values.put(randomID, missing);
}
if (threadRandom.nextDouble() <= reopenChance || rt.size() > 10000) {
//System.out.println("refresh @ " + rt.size());
mgr.maybeRefresh();
if (VERBOSE) {
IndexSearcher s = mgr.acquire();
try {
System.out.println("TEST: reopen " + s);
} finally {
mgr.release(s);
}
System.out.println("TEST: " + values.size() + " values");
}
}
if (threadRandom.nextInt(10) == 7) {
assertEquals(null, rt.get("foo"));
}
if (allIDs.size() > 0) {
String randomID = allIDs.get(threadRandom.nextInt(allIDs.size()));
Integer expected = values.get(randomID);
if (expected == missing) {
expected = null;
}
assertEquals("id=" + randomID, expected, rt.get(randomID));
}
}
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
};
threads.add(thread);
thread.start();
}
startingGun.countDown();
for(Thread thread : threads) {
thread.join();
}
mgr.maybeRefresh();
assertEquals(0, rt.size());
rt.close();
mgr.close();
_w.close();
dir.close();
}
}

View File

@ -423,8 +423,13 @@ public class TestNRTManager extends ThreadedIndexingAndSearchingTestCase {
NRTManager sm = new NRTManager(new NRTManager.TrackingIndexWriter(iw),new SearcherFactory());
sm.addListener(new ReferenceManager.RefreshListener() {
@Override
public void afterRefresh() {
afterRefreshCalled.set(true);
public void beforeRefresh() {
}
@Override
public void afterRefresh(boolean didRefresh) {
if (didRefresh) {
afterRefreshCalled.set(true);
}
}
});
iw.addDocument(new Document());

View File

@ -380,8 +380,8 @@ public class TestNumericRangeQuery32 extends LuceneTestCase {
int a=lower; lower=upper; upper=a;
}
final BytesRef lowerBytes = new BytesRef(NumericUtils.BUF_SIZE_INT), upperBytes = new BytesRef(NumericUtils.BUF_SIZE_INT);
NumericUtils.intToPrefixCoded(lower, 0, lowerBytes);
NumericUtils.intToPrefixCoded(upper, 0, upperBytes);
NumericUtils.intToPrefixCodedBytes(lower, 0, lowerBytes);
NumericUtils.intToPrefixCodedBytes(upper, 0, upperBytes);
// test inclusive range
NumericRangeQuery<Integer> tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, true);

View File

@ -405,8 +405,8 @@ public class TestNumericRangeQuery64 extends LuceneTestCase {
long a=lower; lower=upper; upper=a;
}
final BytesRef lowerBytes = new BytesRef(NumericUtils.BUF_SIZE_LONG), upperBytes = new BytesRef(NumericUtils.BUF_SIZE_LONG);
NumericUtils.longToPrefixCoded(lower, 0, lowerBytes);
NumericUtils.longToPrefixCoded(upper, 0, upperBytes);
NumericUtils.longToPrefixCodedBytes(lower, 0, lowerBytes);
NumericUtils.longToPrefixCodedBytes(upper, 0, upperBytes);
// test inclusive range
NumericRangeQuery<Long> tq=NumericRangeQuery.newLongRange(field, precisionStep, lower, upper, true, true);

View File

@ -331,8 +331,13 @@ public class TestSearcherManager extends ThreadedIndexingAndSearchingTestCase {
SearcherManager sm = new SearcherManager(iw, false, new SearcherFactory());
sm.addListener(new ReferenceManager.RefreshListener() {
@Override
public void afterRefresh() {
afterRefreshCalled.set(true);
public void beforeRefresh() {
}
@Override
public void afterRefresh(boolean didRefresh) {
if (didRefresh) {
afterRefreshCalled.set(true);
}
}
});
iw.addDocument(new Document());

View File

@ -28,7 +28,7 @@ public class TestNumericUtils extends LuceneTestCase {
// generate a series of encoded longs, each numerical one bigger than the one before
BytesRef last=null, act=new BytesRef(NumericUtils.BUF_SIZE_LONG);
for (long l=-100000L; l<100000L; l++) {
NumericUtils.longToPrefixCoded(l, 0, act);
NumericUtils.longToPrefixCodedBytes(l, 0, act);
if (last!=null) {
// test if smaller
assertTrue("actual bigger than last (BytesRef)", last.compareTo(act) < 0 );
@ -46,7 +46,7 @@ public class TestNumericUtils extends LuceneTestCase {
// generate a series of encoded ints, each numerical one bigger than the one before
BytesRef last=null, act=new BytesRef(NumericUtils.BUF_SIZE_INT);
for (int i=-100000; i<100000; i++) {
NumericUtils.intToPrefixCoded(i, 0, act);
NumericUtils.intToPrefixCodedBytes(i, 0, act);
if (last!=null) {
// test if smaller
assertTrue("actual bigger than last (BytesRef)", last.compareTo(act) < 0 );
@ -69,7 +69,7 @@ public class TestNumericUtils extends LuceneTestCase {
for (int i=0; i<vals.length; i++) {
prefixVals[i] = new BytesRef(NumericUtils.BUF_SIZE_LONG);
NumericUtils.longToPrefixCoded(vals[i], 0, prefixVals[i]);
NumericUtils.longToPrefixCodedBytes(vals[i], 0, prefixVals[i]);
// check forward and back conversion
assertEquals( "forward and back conversion should generate same long", vals[i], NumericUtils.prefixCodedToLong(prefixVals[i]) );
@ -92,7 +92,7 @@ public class TestNumericUtils extends LuceneTestCase {
final BytesRef ref = new BytesRef(NumericUtils.BUF_SIZE_LONG);
for (int i=0; i<vals.length; i++) {
for (int j=0; j<64; j++) {
NumericUtils.longToPrefixCoded(vals[i], j, ref);
NumericUtils.longToPrefixCodedBytes(vals[i], j, ref);
long prefixVal=NumericUtils.prefixCodedToLong(ref);
long mask=(1L << j) - 1L;
assertEquals( "difference between prefix val and original value for "+vals[i]+" with shift="+j, vals[i] & mask, vals[i]-prefixVal );
@ -109,7 +109,7 @@ public class TestNumericUtils extends LuceneTestCase {
for (int i=0; i<vals.length; i++) {
prefixVals[i] = new BytesRef(NumericUtils.BUF_SIZE_INT);
NumericUtils.intToPrefixCoded(vals[i], 0, prefixVals[i]);
NumericUtils.intToPrefixCodedBytes(vals[i], 0, prefixVals[i]);
// check forward and back conversion
assertEquals( "forward and back conversion should generate same int", vals[i], NumericUtils.prefixCodedToInt(prefixVals[i]) );
@ -132,7 +132,7 @@ public class TestNumericUtils extends LuceneTestCase {
final BytesRef ref = new BytesRef(NumericUtils.BUF_SIZE_LONG);
for (int i=0; i<vals.length; i++) {
for (int j=0; j<32; j++) {
NumericUtils.intToPrefixCoded(vals[i], j, ref);
NumericUtils.intToPrefixCodedBytes(vals[i], j, ref);
int prefixVal=NumericUtils.prefixCodedToInt(ref);
int mask=(1 << j) - 1;
assertEquals( "difference between prefix val and original value for "+vals[i]+" with shift="+j, vals[i] & mask, vals[i]-prefixVal );

View File

@ -45,17 +45,17 @@ public class TaxonomyMergeUtils {
* opens {@link DirectoryTaxonomyWriter} and {@link IndexWriter} on the
* respective destination indexes. Therefore if you have a writer open on any
* of them, it should be closed, or you should use
* {@link #merge(Directory, Directory, IndexWriter, DirectoryTaxonomyWriter)}
* {@link #merge(Directory, Directory, IndexWriter, DirectoryTaxonomyWriter, FacetIndexingParams)}
* instead.
*
* @see #merge(Directory, Directory, IndexWriter, DirectoryTaxonomyWriter)
* @see #merge(Directory, Directory, IndexWriter, DirectoryTaxonomyWriter, FacetIndexingParams)
*/
public static void merge(Directory srcIndexDir, Directory srcTaxDir,
Directory destIndexDir, Directory destTaxDir) throws IOException {
public static void merge(Directory srcIndexDir, Directory srcTaxDir, Directory destIndexDir, Directory destTaxDir,
FacetIndexingParams params) throws IOException {
IndexWriter destIndexWriter = new IndexWriter(destIndexDir,
new IndexWriterConfig(ExampleUtils.EXAMPLE_VER, null));
DirectoryTaxonomyWriter destTaxWriter = new DirectoryTaxonomyWriter(destTaxDir);
merge(srcIndexDir, srcTaxDir, new MemoryOrdinalMap(), destIndexWriter, destTaxWriter);
merge(srcIndexDir, srcTaxDir, new MemoryOrdinalMap(), destIndexWriter, destTaxWriter, params);
destTaxWriter.close();
destIndexWriter.close();
}
@ -64,30 +64,26 @@ public class TaxonomyMergeUtils {
* Merges the given taxonomy and index directories and commits the changes to
* the given writers. This method uses {@link MemoryOrdinalMap} to store the
* mapped ordinals. If you cannot afford the memory, you can use
* {@link #merge(Directory, Directory, DirectoryTaxonomyWriter.OrdinalMap, IndexWriter, DirectoryTaxonomyWriter)}
* {@link #merge(Directory, Directory, DirectoryTaxonomyWriter.OrdinalMap, IndexWriter, DirectoryTaxonomyWriter, FacetIndexingParams)}
* by passing {@link DiskOrdinalMap}.
*
* @see #merge(Directory, Directory, DirectoryTaxonomyWriter.OrdinalMap, IndexWriter, DirectoryTaxonomyWriter)
* @see #merge(Directory, Directory, DirectoryTaxonomyWriter.OrdinalMap,
* IndexWriter, DirectoryTaxonomyWriter, FacetIndexingParams)
*/
public static void merge(Directory srcIndexDir, Directory srcTaxDir,
IndexWriter destIndexWriter,
DirectoryTaxonomyWriter destTaxWriter) throws IOException {
merge(srcIndexDir, srcTaxDir, new MemoryOrdinalMap(), destIndexWriter, destTaxWriter);
public static void merge(Directory srcIndexDir, Directory srcTaxDir, IndexWriter destIndexWriter,
DirectoryTaxonomyWriter destTaxWriter, FacetIndexingParams params) throws IOException {
merge(srcIndexDir, srcTaxDir, new MemoryOrdinalMap(), destIndexWriter, destTaxWriter, params);
}
/**
* Merges the given taxonomy and index directories and commits the changes to
* the given writers.
*/
public static void merge(Directory srcIndexDir, Directory srcTaxDir,
OrdinalMap map, IndexWriter destIndexWriter,
DirectoryTaxonomyWriter destTaxWriter) throws IOException {
public static void merge(Directory srcIndexDir, Directory srcTaxDir, OrdinalMap map, IndexWriter destIndexWriter,
DirectoryTaxonomyWriter destTaxWriter, FacetIndexingParams params) throws IOException {
// merge the taxonomies
destTaxWriter.addTaxonomy(srcTaxDir, map);
int ordinalMap[] = map.getMap();
FacetIndexingParams params = FacetIndexingParams.ALL_PARENTS;
DirectoryReader reader = DirectoryReader.open(srcIndexDir, -1);
List<AtomicReaderContext> leaves = reader.leaves();
int numReaders = leaves.size();

View File

@ -1,6 +1,5 @@
package org.apache.lucene.facet.example.simple;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@ -17,6 +16,7 @@ import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MultiCollector;
import org.apache.lucene.search.Query;
@ -153,7 +153,7 @@ public class SimpleSearcher {
CategoryPath categoryOfInterest = resIterator.next().label;
// drill-down preparation: turn the base query into a drill-down query for the category of interest
Query q2 = DrillDown.query(indexingParams, baseQuery, categoryOfInterest);
Query q2 = DrillDown.query(indexingParams, baseQuery, Occur.MUST, categoryOfInterest);
// that's it - search with the new query and we're done!
// only documents both matching the base query AND containing the

View File

@ -1,7 +1,6 @@
package org.apache.lucene.facet.index.params;
import java.io.IOException;
import java.io.Serializable;
import org.apache.lucene.facet.search.CategoryListIterator;
import org.apache.lucene.facet.search.DocValuesCategoryListIterator;
@ -34,7 +33,7 @@ import org.apache.lucene.util.encoding.UniqueValuesIntEncoder;
*
* @lucene.experimental
*/
public class CategoryListParams implements Serializable {
public class CategoryListParams {
/** OrdinalPolicy defines which ordinals are encoded for every document. */
public static enum OrdinalPolicy {
@ -143,4 +142,9 @@ public class CategoryListParams implements Serializable {
return DEFAULT_ORDINAL_POLICY;
}
@Override
public String toString() {
return "field=" + field + " encoder=" + createEncoder() + " ordinalPolicy=" + getOrdinalPolicy();
}
}

View File

@ -59,18 +59,23 @@ public final class DrillDown {
}
/**
* Wraps a given {@link Query} as a drill-down query over the given
* categories, assuming all are required (e.g. {@code AND}). You can construct
* a query with different modes (such as {@code OR} or {@code AND} of
* {@code ORs}) by creating a {@link BooleanQuery} and call this method
* several times. Make sure to wrap the query in that case by
* {@link ConstantScoreQuery} and set the boost to 0.0f, so that it doesn't
* affect scoring.
* Wraps a given {@link Query} by a drill-down query over the given
* categories. {@link Occur} defines the relationship between the cateories
* (e.g. {@code OR} or {@code AND}. If you need to construct a more
* complicated relationship, e.g. {@code AND} of {@code ORs}), call this
* method with every group of categories with the same relationship and then
* construct a {@link BooleanQuery} which will wrap all returned queries. It
* is advised to construct that boolean query with coord disabled, and also
* wrap the final query with {@link ConstantScoreQuery} and set its boost to
* {@code 0.0f}.
* <p>
* <b>NOTE:</b> {@link Occur} only makes sense when there is more than one
* {@link CategoryPath} given.
* <p>
* <b>NOTE:</b> {@code baseQuery} can be {@code null}, in which case only the
* {@link Query} over the categories will is returned.
*/
public static final Query query(FacetIndexingParams iParams, Query baseQuery, CategoryPath... paths) {
public static final Query query(FacetIndexingParams iParams, Query baseQuery, Occur occur, CategoryPath... paths) {
if (paths == null || paths.length == 0) {
throw new IllegalArgumentException("Empty category path not allowed for drill down query!");
}
@ -81,7 +86,7 @@ public final class DrillDown {
} else {
BooleanQuery bq = new BooleanQuery(true); // disable coord
for (CategoryPath cp : paths) {
bq.add(new TermQuery(term(iParams, cp)), Occur.MUST);
bq.add(new TermQuery(term(iParams, cp)), occur);
}
q = bq;
}
@ -100,10 +105,10 @@ public final class DrillDown {
}
/**
* @see #query(FacetIndexingParams, Query, CategoryPath...)
* @see #query
*/
public static final Query query(FacetSearchParams sParams, Query baseQuery, CategoryPath... paths) {
return query(sParams.indexingParams, baseQuery, paths);
public static final Query query(FacetSearchParams sParams, Query baseQuery, Occur occur, CategoryPath... paths) {
return query(sParams.indexingParams, baseQuery, occur, paths);
}
}

View File

@ -30,6 +30,7 @@ import org.apache.lucene.store.FSDirectory;
/** Prints how many ords are under each dimension. */
// java -cp ../build/core/classes/java:../build/facet/classes/java org.apache.lucene.facet.util.PrintTaxonomyStats -printTree /s2/scratch/indices/wikibig.trunk.noparents.facets.Lucene41.nd1M/facets
public class PrintTaxonomyStats {
public static void main(String[] args) throws IOException {

View File

@ -86,7 +86,7 @@ public class FourFlagsIntDecoder extends IntDecoder {
@Override
public String toString() {
return "FourFlags(VInt8)";
return "FourFlags(VInt)";
}
}

View File

@ -42,7 +42,6 @@ import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.LuceneTestCase.SuppressCodecs;
import org.apache.lucene.util._TestUtil;
import org.junit.AfterClass;
@ -66,7 +65,7 @@ import org.junit.BeforeClass;
*/
@SuppressCodecs({"SimpleText"})
public abstract class FacetTestBase extends LuceneTestCase {
public abstract class FacetTestBase extends FacetTestCase {
/** Holds a search and taxonomy Directories pair. */
private static final class SearchTaxoDirPair {
@ -92,7 +91,7 @@ public abstract class FacetTestBase extends LuceneTestCase {
@BeforeClass
public static void beforeClassFacetTestBase() {
TEST_DIR = _TestUtil.getTempDir("facets");
dirsPerPartitionSize = new HashMap<Integer, FacetTestBase.SearchTaxoDirPair>();
dirsPerPartitionSize = new HashMap<Integer, FacetTestBase.SearchTaxoDirPair>();
}
@AfterClass
@ -181,8 +180,10 @@ public abstract class FacetTestBase extends LuceneTestCase {
return newIndexWriterConfig(TEST_VERSION_CURRENT, analyzer);
}
/** Returns a default facet indexing params */
/** Returns a {@link FacetIndexingParams} per the given partition size. */
protected FacetIndexingParams getFacetIndexingParams(final int partSize) {
// several of our encoders don't support the value 0,
// which is one of the values encoded when dealing w/ partitions.
return new FacetIndexingParams() {
@Override
public int getPartitionSize() {

View File

@ -0,0 +1,64 @@
package org.apache.lucene.facet;
import java.util.Random;
import org.apache.lucene.facet.index.params.CategoryListParams;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.encoding.DGapIntEncoder;
import org.apache.lucene.util.encoding.DGapVInt8IntEncoder;
import org.apache.lucene.util.encoding.EightFlagsIntEncoder;
import org.apache.lucene.util.encoding.FourFlagsIntEncoder;
import org.apache.lucene.util.encoding.IntEncoder;
import org.apache.lucene.util.encoding.NOnesIntEncoder;
import org.apache.lucene.util.encoding.SortingIntEncoder;
import org.apache.lucene.util.encoding.UniqueValuesIntEncoder;
import org.apache.lucene.util.encoding.VInt8IntEncoder;
/*
* 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.
*/
public class FacetTestCase extends LuceneTestCase {
private static final IntEncoder[] ENCODERS = new IntEncoder[] {
new SortingIntEncoder(new UniqueValuesIntEncoder(new VInt8IntEncoder())),
new SortingIntEncoder(new UniqueValuesIntEncoder(new DGapIntEncoder(new VInt8IntEncoder()))),
new SortingIntEncoder(new UniqueValuesIntEncoder(new DGapVInt8IntEncoder())),
new SortingIntEncoder(new UniqueValuesIntEncoder(new DGapIntEncoder(new EightFlagsIntEncoder()))),
new SortingIntEncoder(new UniqueValuesIntEncoder(new DGapIntEncoder(new FourFlagsIntEncoder()))),
new SortingIntEncoder(new UniqueValuesIntEncoder(new DGapIntEncoder(new NOnesIntEncoder(3)))),
new SortingIntEncoder(new UniqueValuesIntEncoder(new DGapIntEncoder(new NOnesIntEncoder(4)))),
};
/** Returns a {@link CategoryListParams} with random {@link IntEncoder} and field. */
public static CategoryListParams randomCategoryListParams() {
final String field = CategoryListParams.DEFAULT_FIELD + "$" + random().nextInt();
return randomCategoryListParams(field);
}
/** Returns a {@link CategoryListParams} with random {@link IntEncoder}. */
public static CategoryListParams randomCategoryListParams(String field) {
Random random = random();
final IntEncoder encoder = ENCODERS[random.nextInt(ENCODERS.length)];
return new CategoryListParams(field) {
@Override
public IntEncoder createEncoder() {
return encoder;
}
};
}
}

View File

@ -1,30 +1,17 @@
package org.apache.lucene.facet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.facet.index.params.FacetIndexingParams;
import org.apache.lucene.facet.search.FacetsCollector;
import org.apache.lucene.facet.search.params.CountFacetRequest;
import org.apache.lucene.facet.search.params.FacetRequest;
import org.apache.lucene.facet.search.params.FacetSearchParams;
import org.apache.lucene.facet.search.results.FacetResult;
import org.apache.lucene.facet.search.results.FacetResultNode;
import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.MultiCollector;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.LuceneTestCase;
@ -109,30 +96,6 @@ public class FacetTestUtils {
return pairs;
}
public static Collector[] search(IndexSearcher searcher, TaxonomyReader taxonomyReader, FacetIndexingParams iParams,
int k, String... facetNames) throws IOException {
Collector[] collectors = new Collector[2];
List<FacetRequest> fRequests = new ArrayList<FacetRequest>();
for (String facetName : facetNames) {
CategoryPath cp = new CategoryPath(facetName);
FacetRequest fq = new CountFacetRequest(cp, k);
fRequests.add(fq);
}
FacetSearchParams facetSearchParams = new FacetSearchParams(fRequests, iParams);
TopScoreDocCollector topDocsCollector = TopScoreDocCollector.create(searcher.getIndexReader().maxDoc(), true);
FacetsCollector facetsCollector = FacetsCollector.create(facetSearchParams, searcher.getIndexReader(), taxonomyReader);
Collector mColl = MultiCollector.wrap(topDocsCollector, facetsCollector);
collectors[0] = topDocsCollector;
collectors[1] = facetsCollector;
searcher.search(new MatchAllDocsQuery(), mColl);
return collectors;
}
public static String toSimpleString(FacetResult fr) {
StringBuilder sb = new StringBuilder();
toSimpleString(0, sb, fr.getFacetResultNode(), "");

View File

@ -7,16 +7,9 @@ import java.util.List;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.analysis.MockTokenizer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.store.Directory;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.example.merge.TaxonomyMergeUtils;
import org.apache.lucene.facet.index.params.FacetIndexingParams;
import org.apache.lucene.facet.search.FacetsCollector;
import org.apache.lucene.facet.search.params.CountFacetRequest;
import org.apache.lucene.facet.search.params.FacetSearchParams;
@ -25,6 +18,13 @@ import org.apache.lucene.facet.search.results.FacetResultNode;
import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.store.Directory;
import org.junit.Test;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -43,34 +43,35 @@ import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
* limitations under the License.
*/
public class OrdinalMappingReaderTest extends LuceneTestCase {
public class OrdinalMappingReaderTest extends FacetTestCase {
private static final int NUM_DOCS = 100;
@Test
public void testTaxonomyMergeUtils() throws Exception {
Directory dir = newDirectory();
Directory taxDir = newDirectory();
buildIndexWithFacets(dir, taxDir, true);
Directory taxDir = newDirectory();
FacetIndexingParams fip = new FacetIndexingParams(randomCategoryListParams());
buildIndexWithFacets(dir, taxDir, true, fip);
Directory dir1 = newDirectory();
Directory taxDir1 = newDirectory();
buildIndexWithFacets(dir1, taxDir1, false);
buildIndexWithFacets(dir1, taxDir1, false, fip);
TaxonomyMergeUtils.merge(dir, taxDir, dir1, taxDir1);
TaxonomyMergeUtils.merge(dir, taxDir, dir1, taxDir1, fip);
verifyResults(dir1, taxDir1);
verifyResults(dir1, taxDir1, fip);
dir1.close();
taxDir1.close();
dir.close();
taxDir.close();
}
private void verifyResults(Directory dir, Directory taxDir) throws IOException {
private void verifyResults(Directory dir, Directory taxDir, FacetIndexingParams fip) throws IOException {
DirectoryReader reader1 = DirectoryReader.open(dir);
DirectoryTaxonomyReader taxReader = new DirectoryTaxonomyReader(taxDir);
IndexSearcher searcher = newSearcher(reader1);
FacetSearchParams fsp = new FacetSearchParams(new CountFacetRequest(new CategoryPath("tag"), NUM_DOCS));
FacetSearchParams fsp = new FacetSearchParams(fip, new CountFacetRequest(new CategoryPath("tag"), NUM_DOCS));
FacetsCollector collector = FacetsCollector.create(fsp, reader1, taxReader);
searcher.search(new MatchAllDocsQuery(), collector);
FacetResult result = collector.getFacetResults().get(0);
@ -88,7 +89,7 @@ public class OrdinalMappingReaderTest extends LuceneTestCase {
taxReader.close();
}
private void buildIndexWithFacets(Directory dir, Directory taxDir, boolean asc) throws IOException {
private void buildIndexWithFacets(Directory dir, Directory taxDir, boolean asc, FacetIndexingParams fip) throws IOException {
IndexWriterConfig config = newIndexWriterConfig(TEST_VERSION_CURRENT,
new MockAnalyzer(random(), MockTokenizer.WHITESPACE, false));
RandomIndexWriter writer = new RandomIndexWriter(random(), dir, config);
@ -101,7 +102,7 @@ public class OrdinalMappingReaderTest extends LuceneTestCase {
int facetValue = asc? j: NUM_DOCS - j;
categoryPaths.add(new CategoryPath("tag", Integer.toString(facetValue)));
}
FacetFields facetFields = new FacetFields(taxonomyWriter);
FacetFields facetFields = new FacetFields(taxonomyWriter, fip);
facetFields.addFields(doc, categoryPaths);
writer.addDocument(doc);
}

View File

@ -21,6 +21,7 @@ import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.index.params.CategoryListParams;
import org.apache.lucene.facet.index.params.FacetIndexingParams;
import org.apache.lucene.facet.index.params.PerDimensionIndexingParams;
@ -57,11 +58,11 @@ import org.apache.lucene.search.MultiCollector;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TotalHitCountCollector;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.IntsRef;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
/*
@ -82,7 +83,7 @@ import org.junit.Test;
*/
/** Tests facets index migration from payload to DocValues.*/
public class TestFacetsPayloadMigrationReader extends LuceneTestCase {
public class TestFacetsPayloadMigrationReader extends FacetTestCase {
private static class PayloadFacetFields extends FacetFields {
@ -284,7 +285,7 @@ public class TestFacetsPayloadMigrationReader extends LuceneTestCase {
for (String dim : expectedCounts.keySet()) {
CategoryPath drillDownCP = new CategoryPath(dim);
FacetSearchParams fsp = new FacetSearchParams(fip, new CountFacetRequest(drillDownCP, 10));
Query drillDown = DrillDown.query(fsp, new MatchAllDocsQuery(), drillDownCP);
Query drillDown = DrillDown.query(fsp, new MatchAllDocsQuery(), Occur.MUST, drillDownCP);
TotalHitCountCollector total = new TotalHitCountCollector();
FacetsCollector fc = FacetsCollector.create(fsp, indexReader, taxoReader);
searcher.search(drillDown, MultiCollector.wrap(fc, total));

View File

@ -1,6 +1,6 @@
package org.apache.lucene.facet.index.params;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.util.encoding.DGapVInt8IntEncoder;
import org.apache.lucene.util.encoding.IntDecoder;
import org.apache.lucene.util.encoding.IntEncoder;
@ -25,7 +25,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class CategoryListParamsTest extends LuceneTestCase {
public class CategoryListParamsTest extends FacetTestCase {
@Test
public void testDefaultSettings() {

View File

@ -1,10 +1,10 @@
package org.apache.lucene.facet.index.params;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.search.DrillDown;
import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.facet.util.PartitionsUtils;
import org.apache.lucene.index.Term;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
/*
@ -24,7 +24,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class FacetIndexingParamsTest extends LuceneTestCase {
public class FacetIndexingParamsTest extends FacetTestCase {
@Test
public void testDefaultSettings() {

View File

@ -2,11 +2,11 @@ package org.apache.lucene.facet.index.params;
import java.util.Collections;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.search.DrillDown;
import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.facet.util.PartitionsUtils;
import org.apache.lucene.index.Term;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
/*
@ -26,7 +26,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class PerDimensionIndexingParamsTest extends LuceneTestCase {
public class PerDimensionIndexingParamsTest extends FacetTestCase {
@Test
public void testTopLevelSettings() {
@ -41,7 +41,6 @@ public class PerDimensionIndexingParamsTest extends LuceneTestCase {
assertEquals("3 characters should be written", 3, numchars);
assertEquals("wrong drill-down term text", expectedDDText, new String(buf, 0, numchars));
CategoryListParams clParams = ifip.getCategoryListParams(null);
assertEquals("partition for all ordinals is the first", "", PartitionsUtils.partitionNameByOrdinal(ifip, 250));
assertEquals("for partition 0, the same name should be returned", "", PartitionsUtils.partitionName(0));
assertEquals("for any other, it's the concatenation of name + partition", PartitionsUtils.PART_NAME_PREFIX + "1", PartitionsUtils.partitionName(1));

View File

@ -7,13 +7,13 @@ import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.analysis.MockTokenizer;
import org.apache.lucene.document.BinaryDocValuesField;
import org.apache.lucene.document.Document;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.IntsRef;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.encoding.DGapIntEncoder;
import org.apache.lucene.util.encoding.IntEncoder;
import org.apache.lucene.util.encoding.SortingIntEncoder;
@ -38,7 +38,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class CategoryListIteratorTest extends LuceneTestCase {
public class CategoryListIteratorTest extends FacetTestCase {
static final IntsRef[] data = new IntsRef[] {
new IntsRef(new int[] { 1, 2 }, 0, 2),
@ -48,9 +48,9 @@ public class CategoryListIteratorTest extends LuceneTestCase {
};
@Test
public void testPayloadCategoryListIteraor() throws Exception {
public void test() throws Exception {
Directory dir = newDirectory();
final IntEncoder encoder = new SortingIntEncoder(new UniqueValuesIntEncoder(new DGapIntEncoder(new VInt8IntEncoder())));
final IntEncoder encoder = randomCategoryListParams().createEncoder();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir, newIndexWriterConfig(TEST_VERSION_CURRENT,
new MockAnalyzer(random(), MockTokenizer.KEYWORD, false)).setMergePolicy(newLogMergePolicy()));
BytesRef buf = new BytesRef();
@ -89,7 +89,7 @@ public class CategoryListIteratorTest extends LuceneTestCase {
}
@Test
public void testPayloadIteratorWithInvalidDoc() throws Exception {
public void testEmptyDocuments() throws Exception {
Directory dir = newDirectory();
final IntEncoder encoder = new SortingIntEncoder(new UniqueValuesIntEncoder(new DGapIntEncoder(new VInt8IntEncoder())));
// NOTE: test is wired to LogMP... because test relies on certain docids having payloads

View File

@ -13,6 +13,7 @@ import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.StringField;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.index.FacetFields;
import org.apache.lucene.facet.index.params.CategoryListParams;
import org.apache.lucene.facet.index.params.FacetIndexingParams;
@ -40,7 +41,6 @@ import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.ObjectToIntMap;
import org.apache.lucene.util.encoding.IntEncoder;
import org.apache.lucene.util.encoding.VInt8IntEncoder;
@ -65,7 +65,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class CountingFacetsCollectorTest extends LuceneTestCase {
public class CountingFacetsCollectorTest extends FacetTestCase {
private static final Term A = new Term("f", "a");
private static final CategoryPath CP_A = new CategoryPath("A"), CP_B = new CategoryPath("B");

View File

@ -10,6 +10,7 @@ import org.apache.lucene.analysis.MockTokenizer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.index.FacetFields;
import org.apache.lucene.facet.index.params.CategoryListParams;
import org.apache.lucene.facet.index.params.FacetIndexingParams;
@ -26,8 +27,8 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@ -49,9 +50,9 @@ import org.junit.Test;
* limitations under the License.
*/
public class DrillDownTest extends LuceneTestCase {
public class DrillDownTest extends FacetTestCase {
private FacetIndexingParams defaultParams = FacetIndexingParams.ALL_PARENTS;
private FacetIndexingParams defaultParams;
private PerDimensionIndexingParams nonDefaultParams;
private static IndexReader reader;
private static DirectoryTaxonomyReader taxo;
@ -60,9 +61,10 @@ public class DrillDownTest extends LuceneTestCase {
public DrillDownTest() {
Map<CategoryPath,CategoryListParams> paramsMap = new HashMap<CategoryPath,CategoryListParams>();
paramsMap.put(new CategoryPath("a"), new CategoryListParams("testing_facets_a"));
paramsMap.put(new CategoryPath("b"), new CategoryListParams("testing_facets_b"));
paramsMap.put(new CategoryPath("a"), randomCategoryListParams("testing_facets_a"));
paramsMap.put(new CategoryPath("b"), randomCategoryListParams("testing_facets_b"));
nonDefaultParams = new PerDimensionIndexingParams(paramsMap);
defaultParams = new FacetIndexingParams(randomCategoryListParams(CategoryListParams.DEFAULT_FIELD));
}
@BeforeClass
@ -128,25 +130,25 @@ public class DrillDownTest extends LuceneTestCase {
IndexSearcher searcher = newSearcher(reader);
// Making sure the query yields 25 documents with the facet "a"
Query q = DrillDown.query(defaultParams, null, new CategoryPath("a"));
Query q = DrillDown.query(defaultParams, null, Occur.MUST, new CategoryPath("a"));
TopDocs docs = searcher.search(q, 100);
assertEquals(25, docs.totalHits);
// Making sure the query yields 5 documents with the facet "b" and the
// previous (facet "a") query as a base query
Query q2 = DrillDown.query(defaultParams, q, new CategoryPath("b"));
Query q2 = DrillDown.query(defaultParams, q, Occur.MUST, new CategoryPath("b"));
docs = searcher.search(q2, 100);
assertEquals(5, docs.totalHits);
// Making sure that a query of both facet "a" and facet "b" yields 5 results
Query q3 = DrillDown.query(defaultParams, null, new CategoryPath("a"), new CategoryPath("b"));
Query q3 = DrillDown.query(defaultParams, null, Occur.MUST, new CategoryPath("a"), new CategoryPath("b"));
docs = searcher.search(q3, 100);
assertEquals(5, docs.totalHits);
// Check that content:foo (which yields 50% results) and facet/b (which yields 20%)
// would gather together 10 results (10%..)
Query fooQuery = new TermQuery(new Term("content", "foo"));
Query q4 = DrillDown.query(defaultParams, fooQuery, new CategoryPath("b"));
Query q4 = DrillDown.query(defaultParams, fooQuery, Occur.MUST, new CategoryPath("b"));
docs = searcher.search(q4, 100);
assertEquals(10, docs.totalHits);
}
@ -156,18 +158,18 @@ public class DrillDownTest extends LuceneTestCase {
IndexSearcher searcher = newSearcher(reader);
// Create the base query to start with
Query q = DrillDown.query(defaultParams, null, new CategoryPath("a"));
Query q = DrillDown.query(defaultParams, null, Occur.MUST, new CategoryPath("a"));
// Making sure the query yields 5 documents with the facet "b" and the
// previous (facet "a") query as a base query
Query q2 = DrillDown.query(defaultParams, q, new CategoryPath("b"));
Query q2 = DrillDown.query(defaultParams, q, Occur.MUST, new CategoryPath("b"));
TopDocs docs = searcher.search(q2, 100);
assertEquals(5, docs.totalHits);
// Check that content:foo (which yields 50% results) and facet/b (which yields 20%)
// would gather together 10 results (10%..)
Query fooQuery = new TermQuery(new Term("content", "foo"));
Query q4 = DrillDown.query(defaultParams, fooQuery, new CategoryPath("b"));
Query q4 = DrillDown.query(defaultParams, fooQuery, Occur.MUST, new CategoryPath("b"));
docs = searcher.search(q4, 100);
assertEquals(10, docs.totalHits);
}
@ -202,7 +204,7 @@ public class DrillDownTest extends LuceneTestCase {
}
// create a drill-down query with category "a", scores should not change
q = DrillDown.query(defaultParams, q, new CategoryPath("a"));
q = DrillDown.query(defaultParams, q, Occur.MUST, new CategoryPath("a"));
docs = searcher.search(q, reader.maxDoc()); // fetch all available docs to this query
for (ScoreDoc sd : docs.scoreDocs) {
assertEquals("score of doc=" + sd.doc + " modified", scores[sd.doc], sd.score, 0f);
@ -214,11 +216,21 @@ public class DrillDownTest extends LuceneTestCase {
// verify that drill-down queries (with no base query) returns 0.0 score
IndexSearcher searcher = newSearcher(reader);
Query q = DrillDown.query(defaultParams, null, new CategoryPath("a"));
Query q = DrillDown.query(defaultParams, null, Occur.MUST, new CategoryPath("a"));
TopDocs docs = searcher.search(q, reader.maxDoc()); // fetch all available docs to this query
for (ScoreDoc sd : docs.scoreDocs) {
assertEquals(0f, sd.score, 0f);
}
}
@Test
public void testOrQuery() throws Exception {
IndexSearcher searcher = newSearcher(reader);
// Making sure that a query of facet "a" or facet "b" yields 0 results
Query q = DrillDown.query(defaultParams, null, Occur.SHOULD, new CategoryPath("a"), new CategoryPath("b"));
TopDocs docs = searcher.search(q, 100);
assertEquals(40, docs.totalHits);
}
}

View File

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.document.Document;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.FacetTestUtils;
import org.apache.lucene.facet.index.FacetFields;
import org.apache.lucene.facet.search.params.CountFacetRequest;
@ -39,14 +40,14 @@ import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.LuceneTestCase;
public class TestDemoFacets extends LuceneTestCase {
public class TestDemoFacets extends FacetTestCase {
private DirectoryTaxonomyWriter taxoWriter;
private RandomIndexWriter writer;
private FacetFields docBuilder;
private FacetFields facetFields;
private void add(String ... categoryPaths) throws IOException {
Document doc = new Document();
@ -55,7 +56,7 @@ public class TestDemoFacets extends LuceneTestCase {
for(String categoryPath : categoryPaths) {
paths.add(new CategoryPath(categoryPath, '/'));
}
docBuilder.addFields(doc, paths);
facetFields.addFields(doc, paths);
writer.addDocument(doc);
}
@ -70,7 +71,7 @@ public class TestDemoFacets extends LuceneTestCase {
// Reused across documents, to add the necessary facet
// fields:
docBuilder = new FacetFields(taxoWriter);
facetFields = new FacetFields(taxoWriter);
add("Author/Bob", "Publish Date/2010/10/15");
add("Author/Lisa", "Publish Date/2010/10/20");
@ -111,7 +112,7 @@ public class TestDemoFacets extends LuceneTestCase {
// Now user drills down on Publish Date/2010:
fsp = new FacetSearchParams(new CountFacetRequest(new CategoryPath("Author"), 10));
Query q2 = DrillDown.query(fsp, new MatchAllDocsQuery(), new CategoryPath("Publish Date/2010", '/'));
Query q2 = DrillDown.query(fsp, new MatchAllDocsQuery(), Occur.MUST, new CategoryPath("Publish Date/2010", '/'));
c = FacetsCollector.create(fsp, searcher.getIndexReader(), taxoReader);
searcher.search(q2, c);
results = c.getFacetResults();

View File

@ -1,6 +1,6 @@
package org.apache.lucene.facet.search;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
/*
@ -20,7 +20,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class TestFacetArrays extends LuceneTestCase {
public class TestFacetArrays extends FacetTestCase {
@Test
public void testFacetArrays() {

View File

@ -123,15 +123,10 @@ public class TestFacetsAccumulatorWithComplement extends FacetTestBase {
}
private FacetSearchParams getFacetSearchParams() {
return new FacetSearchParams(new CountFacetRequest(new CategoryPath("root","a"), 10));
}
/** compute facets with certain facet requests and docs */
private List<FacetResult> findFacets(ScoredDocIDs sDocids, boolean withComplement) throws IOException {
FacetsAccumulator fAccumulator =
new StandardFacetsAccumulator(getFacetSearchParams(), indexReader, taxoReader);
FacetSearchParams fsp = new FacetSearchParams(getFacetIndexingParams(Integer.MAX_VALUE), new CountFacetRequest(new CategoryPath("root","a"), 10));
FacetsAccumulator fAccumulator = new StandardFacetsAccumulator(fsp, indexReader, taxoReader);
fAccumulator.setComplementThreshold(
withComplement ?

View File

@ -7,6 +7,7 @@ import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.StringField;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.index.FacetFields;
import org.apache.lucene.facet.search.params.FacetSearchParams;
import org.apache.lucene.facet.search.params.ScoreFacetRequest;
@ -24,7 +25,6 @@ import org.apache.lucene.search.MultiCollector;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
/*
@ -44,7 +44,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class TestFacetsCollector extends LuceneTestCase {
public class TestFacetsCollector extends FacetTestCase {
@Test
public void testFacetsWithDocScore() throws Exception {

View File

@ -13,6 +13,7 @@ import org.apache.lucene.analysis.MockTokenizer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.FacetTestUtils;
import org.apache.lucene.facet.index.FacetFields;
import org.apache.lucene.facet.index.params.CategoryListParams;
@ -41,7 +42,6 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
/*
@ -61,7 +61,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class TestMultipleCategoryLists extends LuceneTestCase {
public class TestMultipleCategoryLists extends FacetTestCase {
private static final CategoryPath[] CATEGORIES = new CategoryPath[] {
new CategoryPath("Author", "Mark Twain"),

View File

@ -4,24 +4,18 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.junit.Before;
import org.junit.Test;
import org.apache.lucene.facet.FacetTestBase;
import org.apache.lucene.facet.search.FacetsAccumulator;
import org.apache.lucene.facet.search.ScoredDocIDs;
import org.apache.lucene.facet.search.ScoredDocIDsIterator;
import org.apache.lucene.facet.search.ScoredDocIdCollector;
import org.apache.lucene.facet.search.StandardFacetsAccumulator;
import org.apache.lucene.facet.search.params.CountFacetRequest;
import org.apache.lucene.facet.search.params.FacetSearchParams;
import org.apache.lucene.facet.search.params.ScoreFacetRequest;
import org.apache.lucene.facet.search.results.FacetResult;
import org.apache.lucene.facet.search.results.FacetResultNode;
import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.junit.Before;
import org.junit.Test;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -65,8 +59,7 @@ public class TestScoredDocIdCollector extends FacetTestBase {
System.out.println("Query: " + q);
}
float constScore = 17.0f;
ScoredDocIdCollector dCollector = ScoredDocIdCollector.create(indexReader
.maxDoc(), false); // scoring is disabled
ScoredDocIdCollector dCollector = ScoredDocIdCollector.create(indexReader.maxDoc(), false); // scoring is disabled
dCollector.setDefaultScore(constScore);
searcher.search(q, dCollector);
@ -75,13 +68,16 @@ public class TestScoredDocIdCollector extends FacetTestBase {
assertEquals("Wrong number of matching documents!", 2, scoredDocIDs.size());
ScoredDocIDsIterator docItr = scoredDocIDs.iterator();
while (docItr.next()) {
assertEquals("Wrong score for doc " + docItr.getDocID(), constScore,
docItr.getScore(), Double.MIN_VALUE);
assertEquals("Wrong score for doc " + docItr.getDocID(), constScore, docItr.getScore(), Double.MIN_VALUE);
}
// verify by facet values
List<FacetResult> countRes = findFacets(scoredDocIDs, getFacetSearchParams());
List<FacetResult> scoreRes = findFacets(scoredDocIDs, sumScoreSearchParams());
CategoryPath cp = new CategoryPath("root","a");
FacetSearchParams countFSP = new FacetSearchParams(getFacetIndexingParams(Integer.MAX_VALUE), new CountFacetRequest(cp, 10));
FacetSearchParams scoreFSP = new FacetSearchParams(getFacetIndexingParams(Integer.MAX_VALUE), new ScoreFacetRequest(cp, 10));
List<FacetResult> countRes = findFacets(scoredDocIDs, countFSP);
List<FacetResult> scoreRes = findFacets(scoredDocIDs, scoreFSP);
assertEquals("Wrong number of facet count results!", 1, countRes.size());
assertEquals("Wrong number of facet score results!", 1, scoreRes.size());
@ -151,14 +147,4 @@ public class TestScoredDocIdCollector extends FacetTestBase {
}
}
/* use a scoring aggregator */
private FacetSearchParams sumScoreSearchParams() {
// this will use default faceted indexing params, not altering anything about indexing
return new FacetSearchParams(new ScoreFacetRequest(new CategoryPath("root", "a"), 10));
}
private FacetSearchParams getFacetSearchParams() {
return new FacetSearchParams(new CountFacetRequest(new CategoryPath("root","a"), 10));
}
}
}

View File

@ -8,6 +8,7 @@ import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.StringField;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.index.FacetFields;
import org.apache.lucene.facet.index.params.CategoryListParams;
import org.apache.lucene.facet.index.params.FacetIndexingParams;
@ -32,7 +33,6 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
/*
@ -52,7 +52,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class TestStandardFacetsAccumulator extends LuceneTestCase {
public class TestStandardFacetsAccumulator extends FacetTestCase {
private void indexTwoDocs(IndexWriter indexWriter, FacetFields facetFields, boolean withContent) throws Exception {
for (int i = 0; i < 2; i++) {

View File

@ -9,6 +9,7 @@ import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.index.FacetFields;
import org.apache.lucene.facet.index.params.FacetIndexingParams;
import org.apache.lucene.facet.search.params.CountFacetRequest;
@ -30,7 +31,6 @@ import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
/*
@ -50,7 +50,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class TestTopKInEachNodeResultHandler extends LuceneTestCase {
public class TestTopKInEachNodeResultHandler extends FacetTestCase {
//TODO (Facet): Move to extend BaseTestTopK and separate to several smaller test cases (methods) - see TestTopKResultsHandler

View File

@ -4,13 +4,13 @@ import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.FacetTestUtils;
import org.apache.lucene.facet.FacetTestUtils.IndexTaxonomyReaderPair;
import org.apache.lucene.facet.FacetTestUtils.IndexTaxonomyWriterPair;
import org.apache.lucene.facet.index.params.FacetIndexingParams;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util._TestUtil;
import org.junit.Test;
@ -31,7 +31,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class TestTotalFacetCounts extends LuceneTestCase {
public class TestTotalFacetCounts extends FacetTestCase {
private static void initCache(int numEntries) {
TotalFacetCountsCache.getSingleton().clear();
@ -53,8 +53,7 @@ public class TestTotalFacetCounts extends LuceneTestCase {
// Create temporary RAMDirectories
Directory[][] dirs = FacetTestUtils.createIndexTaxonomyDirs(1);
// Create our index/taxonomy writers
IndexTaxonomyWriterPair[] writers = FacetTestUtils
.createIndexTaxonomyWriterPair(dirs);
IndexTaxonomyWriterPair[] writers = FacetTestUtils.createIndexTaxonomyWriterPair(dirs);
FacetIndexingParams iParams = new FacetIndexingParams() {
@Override
public int getPartitionSize() {

View File

@ -8,6 +8,7 @@ import java.util.List;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.analysis.MockTokenizer;
import org.apache.lucene.document.Document;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.FacetTestUtils;
import org.apache.lucene.facet.FacetTestUtils.IndexTaxonomyReaderPair;
import org.apache.lucene.facet.FacetTestUtils.IndexTaxonomyWriterPair;
@ -32,7 +33,6 @@ import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.MockDirectoryWrapper;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.SlowRAMDirectory;
import org.apache.lucene.util._TestUtil;
import org.junit.Before;
@ -55,7 +55,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class TestTotalFacetCountsCache extends LuceneTestCase {
public class TestTotalFacetCountsCache extends FacetTestCase {
static final TotalFacetCountsCache TFC = TotalFacetCountsCache.getSingleton();

View File

@ -5,6 +5,7 @@ import java.util.List;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.analysis.MockTokenizer;
import org.apache.lucene.document.Document;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.associations.AssociationsFacetFields;
import org.apache.lucene.facet.associations.CategoryAssociationsContainer;
import org.apache.lucene.facet.associations.CategoryFloatAssociation;
@ -47,7 +48,7 @@ import org.junit.Test;
*/
/** Test for associations */
public class AssociationsFacetRequestTest extends LuceneTestCase {
public class AssociationsFacetRequestTest extends FacetTestCase {
private static Directory dir;
private static IndexReader reader;

View File

@ -1,15 +1,14 @@
package org.apache.lucene.facet.search.params;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.search.FacetResultsHandler;
import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.junit.Test;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -28,7 +27,7 @@ import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
* limitations under the License.
*/
public class FacetRequestTest extends LuceneTestCase {
public class FacetRequestTest extends FacetTestCase {
@Test(expected=IllegalArgumentException.class)
public void testIllegalNumResults() throws Exception {

View File

@ -1,6 +1,6 @@
package org.apache.lucene.facet.search.params;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
/*
@ -20,7 +20,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class FacetSearchParamsTest extends LuceneTestCase {
public class FacetSearchParamsTest extends FacetTestCase {
@Test
public void testSearchParamsWithNullRequest() throws Exception {

View File

@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.Random;
import org.apache.lucene.document.Document;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.index.FacetFields;
import org.apache.lucene.facet.index.params.CategoryListParams;
import org.apache.lucene.facet.index.params.PerDimensionIndexingParams;
@ -22,7 +23,6 @@ import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.IntsRef;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.encoding.IntDecoder;
import org.junit.Test;
@ -43,7 +43,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class MultiCategoryListIteratorTest extends LuceneTestCase {
public class MultiCategoryListIteratorTest extends FacetTestCase {
@Test
public void testMultipleCategoryLists() throws Exception {
@ -58,7 +58,7 @@ public class MultiCategoryListIteratorTest extends LuceneTestCase {
HashMap<CategoryPath,CategoryListParams> clps = new HashMap<CategoryPath,CategoryListParams>();
for (String dim : dimensions) {
CategoryPath cp = new CategoryPath(dim);
CategoryListParams clp = new CategoryListParams("$" + dim);
CategoryListParams clp = randomCategoryListParams("$" + dim);
clps.put(cp, clp);
}
PerDimensionIndexingParams indexingParams = new PerDimensionIndexingParams(clps);

View File

@ -5,7 +5,9 @@ import java.util.Collections;
import org.apache.lucene.analysis.core.KeywordAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.index.FacetFields;
import org.apache.lucene.facet.index.params.FacetIndexingParams;
import org.apache.lucene.facet.search.FacetsAccumulator;
import org.apache.lucene.facet.search.FacetsCollector;
import org.apache.lucene.facet.search.StandardFacetsCollector;
@ -20,7 +22,6 @@ import org.apache.lucene.facet.taxonomy.TaxonomyReader;
import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
@ -28,9 +29,7 @@ import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
/*
@ -50,16 +49,18 @@ import org.junit.Test;
* limitations under the License.
*/
public class OversampleWithDepthTest extends LuceneTestCase {
public class OversampleWithDepthTest extends FacetTestCase {
@Test
public void testCountWithdepthUsingSampling() throws Exception, IOException {
Directory indexDir = newDirectory();
Directory taxoDir = newDirectory();
FacetIndexingParams fip = new FacetIndexingParams(randomCategoryListParams());
// index 100 docs, each with one category: ["root", docnum/10, docnum]
// e.g. root/8/87
index100Docs(indexDir, taxoDir);
index100Docs(indexDir, taxoDir, fip);
DirectoryReader r = DirectoryReader.open(indexDir);
TaxonomyReader tr = new DirectoryTaxonomyReader(taxoDir);
@ -69,7 +70,7 @@ public class OversampleWithDepthTest extends LuceneTestCase {
facetRequest.setDepth(2);
facetRequest.setResultMode(ResultMode.PER_NODE_IN_TREE);
FacetSearchParams fsp = new FacetSearchParams(facetRequest);
FacetSearchParams fsp = new FacetSearchParams(fip, facetRequest);
// Craft sampling params to enforce sampling
final SamplingParams params = new SamplingParams();
@ -93,13 +94,12 @@ public class OversampleWithDepthTest extends LuceneTestCase {
IOUtils.close(r, tr, indexDir, taxoDir);
}
private void index100Docs(Directory indexDir, Directory taxoDir)
throws CorruptIndexException, LockObtainFailedException, IOException {
private void index100Docs(Directory indexDir, Directory taxoDir, FacetIndexingParams fip) throws IOException {
IndexWriterConfig iwc = newIndexWriterConfig(TEST_VERSION_CURRENT, new KeywordAnalyzer());
IndexWriter w = new IndexWriter(indexDir, iwc);
TaxonomyWriter tw = new DirectoryTaxonomyWriter(taxoDir);
FacetFields facetFields = new FacetFields(tw);
FacetFields facetFields = new FacetFields(tw, fip);
for (int i = 0; i < 100; i++) {
Document doc = new Document();
CategoryPath cp = new CategoryPath("root",Integer.toString(i / 10), Integer.toString(i));

View File

@ -1,6 +1,6 @@
package org.apache.lucene.facet.taxonomy;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
/*
@ -20,7 +20,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class TestCategoryPath extends LuceneTestCase {
public class TestCategoryPath extends FacetTestCase {
@Test
public void testBasic() {

View File

@ -7,13 +7,13 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
import org.apache.lucene.facet.taxonomy.directory.ParallelTaxonomyArrays;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.LuceneTestCase.SuppressCodecs;
import org.apache.lucene.util.SlowRAMDirectory;
import org.junit.Test;
@ -37,7 +37,7 @@ import org.junit.Test;
// TODO: remove this suppress if we fix the TaxoWriter Codec to a non-default (see todo in DirTW)
@SuppressCodecs("SimpleText")
public class TestTaxonomyCombined extends LuceneTestCase {
public class TestTaxonomyCombined extends FacetTestCase {
/** The following categories will be added to the taxonomy by
fillTaxonomy(), and tested by all tests below:

View File

@ -5,13 +5,13 @@ import java.util.HashSet;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter.DiskOrdinalMap;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter.MemoryOrdinalMap;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter.OrdinalMap;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util._TestUtil;
/*
@ -31,7 +31,7 @@ import org.apache.lucene.util._TestUtil;
* limitations under the License.
*/
public class TestAddTaxonomy extends LuceneTestCase {
public class TestAddTaxonomy extends FacetTestCase {
private void dotest(int ncats, final int range) throws Exception {
final AtomicInteger numCats = new AtomicInteger(ncats);

View File

@ -8,6 +8,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.lucene.document.Document;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.index.FacetFields;
import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.facet.taxonomy.writercache.TaxonomyWriterCache;
@ -17,7 +18,6 @@ import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -37,7 +37,7 @@ import org.apache.lucene.util.LuceneTestCase;
*/
/** Tests concurrent indexing with facets. */
public class TestConcurrentFacetedIndexing extends LuceneTestCase {
public class TestConcurrentFacetedIndexing extends FacetTestCase {
// A No-Op TaxonomyWriterCache which always discards all given categories, and
// always returns true in put(), to indicate some cache entries were cleared.

View File

@ -4,19 +4,19 @@ import java.io.IOException;
import java.util.Random;
import org.apache.lucene.analysis.core.KeywordAnalyzer;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LogByteSizeMergePolicy;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.LogByteSizeMergePolicy;
import org.apache.lucene.index.LogMergePolicy;
import org.apache.lucene.store.AlreadyClosedException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
/*
@ -36,7 +36,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class TestDirectoryTaxonomyReader extends LuceneTestCase {
public class TestDirectoryTaxonomyReader extends FacetTestCase {
@Test
public void testCloseAfterIncRef() throws Exception {

View File

@ -7,6 +7,7 @@ import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter.MemoryOrdinalMap;
@ -21,7 +22,6 @@ import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.SegmentInfos;
import org.apache.lucene.store.AlreadyClosedException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
/*
@ -41,7 +41,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class TestDirectoryTaxonomyWriter extends LuceneTestCase {
public class TestDirectoryTaxonomyWriter extends FacetTestCase {
// A No-Op TaxonomyWriterCache which always discards all given categories, and
// always returns true in put(), to indicate some cache entries were cleared.

View File

@ -9,11 +9,9 @@ import java.nio.ByteBuffer;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import org.junit.Test;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.facet.taxonomy.writercache.cl2o.CharBlockArray;
import org.junit.Test;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -32,7 +30,7 @@ import org.apache.lucene.facet.taxonomy.writercache.cl2o.CharBlockArray;
* limitations under the License.
*/
public class TestCharBlockArray extends LuceneTestCase {
public class TestCharBlockArray extends FacetTestCase {
@Test public void testArray() throws Exception {
CharBlockArray array = new CharBlockArray();

View File

@ -8,14 +8,11 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.junit.Test;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util._TestUtil;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.taxonomy.CategoryPath;
import org.apache.lucene.facet.taxonomy.writercache.cl2o.CompactLabelToOrdinal;
import org.apache.lucene.facet.taxonomy.writercache.cl2o.LabelToOrdinal;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util._TestUtil;
import org.junit.Test;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -34,7 +31,7 @@ import org.apache.lucene.facet.taxonomy.writercache.cl2o.LabelToOrdinal;
* limitations under the License.
*/
public class TestCompactLabelToOrdinal extends LuceneTestCase {
public class TestCompactLabelToOrdinal extends FacetTestCase {
@Test
public void testL2O() throws Exception {

View File

@ -9,6 +9,7 @@ import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.StringField;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.facet.search.ScoredDocIDs;
import org.apache.lucene.facet.search.ScoredDocIDsIterator;
import org.apache.lucene.facet.search.ScoredDocIdCollector;
@ -25,7 +26,6 @@ import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
/*
@ -45,7 +45,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class TestScoredDocIDsUtils extends LuceneTestCase {
public class TestScoredDocIDsUtils extends FacetTestCase {
@Test
public void testComplementIterator() throws Exception {

View File

@ -3,11 +3,9 @@ package org.apache.lucene.util;
import java.io.IOException;
import java.util.Arrays;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.UnsafeByteArrayInputStream;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -25,7 +23,7 @@ import org.apache.lucene.util.UnsafeByteArrayInputStream;
* limitations under the License.
*/
public class UnsafeByteArrayInputStreamTest extends LuceneTestCase {
public class UnsafeByteArrayInputStreamTest extends FacetTestCase {
@Test
public void testSimple() throws IOException {

View File

@ -2,11 +2,9 @@ package org.apache.lucene.util;
import java.io.IOException;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.UnsafeByteArrayOutputStream;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -24,7 +22,7 @@ import org.apache.lucene.util.UnsafeByteArrayOutputStream;
* limitations under the License.
*/
public class UnsafeByteArrayOutputStreamTest extends LuceneTestCase {
public class UnsafeByteArrayOutputStreamTest extends FacetTestCase {
@Test
public void testSimpleWrite() throws IOException {

View File

@ -4,11 +4,9 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.ArrayHashMap;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -26,7 +24,7 @@ import org.apache.lucene.util.collections.ArrayHashMap;
* limitations under the License.
*/
public class ArrayHashMapTest extends LuceneTestCase {
public class ArrayHashMapTest extends FacetTestCase {
public static final int RANDOM_TEST_NUM_ITERATIONS = 100; // set to 100,000 for deeper test

View File

@ -1,13 +1,11 @@
package org.apache.lucene.util.collections;
import org.junit.Test;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.FloatIterator;
import org.apache.lucene.util.collections.FloatToObjectMap;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -26,7 +24,7 @@ import org.apache.lucene.util.collections.FloatToObjectMap;
* limitations under the License.
*/
public class FloatToObjectMapTest extends LuceneTestCase {
public class FloatToObjectMapTest extends FacetTestCase {
@Test
public void test0() {

View File

@ -1,10 +1,8 @@
package org.apache.lucene.util.collections;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.IntArray;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -22,7 +20,7 @@ import org.apache.lucene.util.collections.IntArray;
* limitations under the License.
*/
public class IntArrayTest extends LuceneTestCase {
public class IntArrayTest extends FacetTestCase {
@Test
public void test0() {

View File

@ -2,11 +2,9 @@ package org.apache.lucene.util.collections;
import java.util.HashSet;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.IntHashSet;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -24,7 +22,7 @@ import org.apache.lucene.util.collections.IntHashSet;
* limitations under the License.
*/
public class IntHashSetTest extends LuceneTestCase {
public class IntHashSetTest extends FacetTestCase {
@Test
public void test0() {

View File

@ -1,15 +1,11 @@
package org.apache.lucene.util.collections;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.DoubleIterator;
import org.apache.lucene.util.collections.IntIterator;
import org.apache.lucene.util.collections.IntToDoubleMap;
import java.util.HashSet;
import java.util.Random;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -27,7 +23,8 @@ import java.util.Random;
* limitations under the License.
*/
public class IntToDoubleMapTest extends LuceneTestCase {
public class IntToDoubleMapTest extends FacetTestCase {
private static void assertGround(double value) {
assertEquals(IntToDoubleMap.GROUND, value, Double.MAX_VALUE);
}

View File

@ -1,15 +1,11 @@
package org.apache.lucene.util.collections;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.FloatIterator;
import org.apache.lucene.util.collections.IntIterator;
import org.apache.lucene.util.collections.IntToFloatMap;
import java.util.HashSet;
import java.util.Random;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -27,7 +23,8 @@ import java.util.Random;
* limitations under the License.
*/
public class IntToFloatMapTest extends LuceneTestCase {
public class IntToFloatMapTest extends FacetTestCase {
private static void assertGround(float value) {
assertEquals(IntToFloatMap.GROUND, value, Float.MAX_VALUE);
}

View File

@ -1,12 +1,10 @@
package org.apache.lucene.util.collections;
import org.junit.Test;
import java.util.HashSet;
import java.util.Random;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.IntIterator;
import org.apache.lucene.util.collections.IntToIntMap;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -25,7 +23,7 @@ import org.apache.lucene.util.collections.IntToIntMap;
* limitations under the License.
*/
public class IntToIntMapTest extends LuceneTestCase {
public class IntToIntMapTest extends FacetTestCase {
private static void assertGround(int value) {
assertEquals(IntToIntMap.GROUD, value);

View File

@ -4,12 +4,9 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.IntIterator;
import org.apache.lucene.util.collections.IntToObjectMap;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -27,7 +24,7 @@ import org.apache.lucene.util.collections.IntToObjectMap;
* limitations under the License.
*/
public class IntToObjectMapTest extends LuceneTestCase {
public class IntToObjectMapTest extends FacetTestCase {
@Test
public void test0() {

View File

@ -1,15 +1,12 @@
package org.apache.lucene.util.collections;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.FloatIterator;
import org.apache.lucene.util.collections.ObjectToFloatMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -27,7 +24,7 @@ import java.util.Random;
* limitations under the License.
*/
public class ObjectToFloatMapTest extends LuceneTestCase {
public class ObjectToFloatMapTest extends FacetTestCase {
@Test
public void test0() {

View File

@ -6,6 +6,7 @@ import java.util.Random;
import org.junit.Test;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.IntIterator;
import org.apache.lucene.util.collections.ObjectToIntMap;
@ -27,7 +28,7 @@ import org.apache.lucene.util.collections.ObjectToIntMap;
* limitations under the License.
*/
public class ObjectToIntMapTest extends LuceneTestCase {
public class ObjectToIntMapTest extends FacetTestCase {
@Test
public void test0() {

View File

@ -1,10 +1,8 @@
package org.apache.lucene.util.collections;
import org.apache.lucene.facet.FacetTestCase;
import org.junit.Test;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.collections.LRUHashMap;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -22,7 +20,7 @@ import org.apache.lucene.util.collections.LRUHashMap;
* limitations under the License.
*/
public class TestLRUHashMap extends LuceneTestCase {
public class TestLRUHashMap extends FacetTestCase {
// testLRU() tests that the specified size limit is indeed honored, and
// the remaining objects in the map are indeed those that have been most
// recently used

View File

@ -3,9 +3,9 @@ package org.apache.lucene.util.encoding;
import java.io.IOException;
import java.util.Arrays;
import org.apache.lucene.facet.FacetTestCase;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.IntsRef;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.BeforeClass;
import org.junit.Test;
@ -26,7 +26,7 @@ import org.junit.Test;
* limitations under the License.
*/
public class EncodingTest extends LuceneTestCase {
public class EncodingTest extends FacetTestCase {
private static IntsRef uniqueSortedData, data;

View File

@ -63,6 +63,9 @@ Detailed Change List
New Features
----------------------
* SOLR-4043: Add ability to get success/failure responses from Collections API.
(Raintung Li, Mark Miller)
Bug Fixes
----------------------
@ -80,6 +83,16 @@ Bug Fixes
* SOLR-4349 : Admin UI - Query Interface does not work in IE
(steffkes)
* SOLR-4359: The RecentUpdates#update method should treat a problem reading the
next record the same as a problem parsing the record - log the exception and
break. (Mark Miller)
* SOLR-4225: Term info page under schema browser shows incorrect count of terms
(steffkes)
* SOLR-3926: Solr should support better way of finding active sorts (Eirik Lygre via
Erick Erickson)
Optimizations
----------------------
@ -100,6 +113,8 @@ Other Changes
* SOLR-4348: Make the lock type configurable by system property by default.
(Mark Miller)
* SOLR-4353: Renamed example jetty context file to reduce confusion (hossman)
================== 4.1.0 ==================
Versions of Major Components
@ -607,6 +622,9 @@ Bug Fixes
* SOLR-4266: HttpSolrServer does not release connection properly on exception
when no response parser is used. (Steve Molloy via Mark Miller)
* SOLR-2298: Updated JavaDoc for SolrDocument.addField and SolrInputDocument.addField
to have more information on name and value parameters. (Siva Natarajan)
Other Changes
----------------------

View File

@ -17,7 +17,6 @@
package org.apache.solr.handler.dataimport;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import java.net.URLEncoder;
@ -109,58 +108,63 @@ public class TestBuiltInEvaluators extends AbstractDataImportHandlerTestCase {
}
private Date getNow() {
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"),
Locale.ROOT);
private Date twoDaysAgo(Locale l, TimeZone tz) {
Calendar calendar = Calendar.getInstance(tz, l);
calendar.add(Calendar.DAY_OF_YEAR, -2);
return calendar.getTime();
}
@Test
@Ignore("fails if somewhere on earth is a DST change")
public void testDateFormatEvaluator() {
Evaluator dateFormatEval = new DateFormatEvaluator();
ContextImpl context = new ContextImpl(null, resolver, null,
Context.FULL_DUMP, Collections.<String,Object> emptyMap(), null, null);
String currentLocale = Locale.getDefault().toString();
Locale rootLocale = Locale.ROOT;
Locale defaultLocale = Locale.getDefault();
TimeZone defaultTz = TimeZone.getDefault();
{
{
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH", Locale.ROOT);
String sdf = sdfDate.format(getNow());
String dfe = dateFormatEval.evaluate("'NOW-2DAYS','yyyy-MM-dd HH'", context);
assertEquals(sdf,dfe);
}
{
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH", Locale.getDefault());
String sdf = sdfDate.format(getNow());
String dfe = dateFormatEval.evaluate("'NOW-2DAYS','yyyy-MM-dd HH','"+ currentLocale + "'", context);
assertEquals(sdf,dfe);
for(String tz : TimeZone.getAvailableIDs()) {
sdfDate.setTimeZone(TimeZone.getTimeZone(tz));
sdf = sdfDate.format(getNow());
dfe = dateFormatEval.evaluate("'NOW-2DAYS','yyyy-MM-dd HH','" + currentLocale + "','" + tz + "'", context);
assertEquals(sdf,dfe);
}
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH", rootLocale);
String sdf = sdfDate.format(twoDaysAgo(rootLocale, defaultTz));
String dfe = dateFormatEval.evaluate("'NOW-2DAYS','yyyy-MM-dd HH'", context);
assertEquals(sdf,dfe);
}
{
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH", defaultLocale);
String sdf = sdfDate.format(twoDaysAgo(defaultLocale, TimeZone.getDefault()));
String dfe = dateFormatEval.evaluate(
"'NOW-2DAYS','yyyy-MM-dd HH','" + defaultLocale + "'", context);
assertEquals(sdf,dfe);
for(String tzStr : TimeZone.getAvailableIDs()) {
TimeZone tz = TimeZone.getTimeZone(tzStr);
sdfDate.setTimeZone(tz);
sdf = sdfDate.format(twoDaysAgo(defaultLocale, tz));
dfe = dateFormatEval.evaluate(
"'NOW-2DAYS','yyyy-MM-dd HH','" + defaultLocale + "','" + tzStr + "'", context);
assertEquals(sdf,dfe);
}
}
Date d = new Date();
Map<String,Object> map = new HashMap<String,Object>();
map.put("key", d);
resolver.addNamespace("A", map);
assertEquals(
new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ROOT).format(d),
new SimpleDateFormat("yyyy-MM-dd HH:mm", rootLocale).format(d),
dateFormatEval.evaluate("A.key, 'yyyy-MM-dd HH:mm'", context));
assertEquals(
new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(d),
dateFormatEval.evaluate("A.key, 'yyyy-MM-dd HH:mm','" + currentLocale
+ "'", context));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
for(String tz : TimeZone.getAvailableIDs()) {
sdf.setTimeZone(TimeZone.getTimeZone(tz));
new SimpleDateFormat("yyyy-MM-dd HH:mm", defaultLocale).format(d),
dateFormatEval.evaluate("A.key, 'yyyy-MM-dd HH:mm','" + defaultLocale + "'", context));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", defaultLocale);
for(String tzStr : TimeZone.getAvailableIDs()) {
TimeZone tz = TimeZone.getTimeZone(tzStr);
sdf.setTimeZone(tz);
assertEquals(
sdf.format(d),
dateFormatEval.evaluate("A.key, 'yyyy-MM-dd HH:mm','" + currentLocale + "', '" + tz + "'", context));
dateFormatEval.evaluate(
"A.key, 'yyyy-MM-dd HH:mm','" + defaultLocale + "', '" + tzStr + "'", context));
}

View File

@ -48,6 +48,8 @@ public class DistributedQueue {
private final String prefix = "qn-";
private final String response_prefix = "qnr-" ;
public DistributedQueue(SolrZkClient zookeeper, String dir, List<ACL> acl) {
this.dir = dir;
@ -100,7 +102,7 @@ public class DistributedQueue {
*
* @return the data at the head of the queue.
*/
public byte[] element() throws NoSuchElementException, KeeperException,
private QueueEvent element() throws NoSuchElementException, KeeperException,
InterruptedException {
TreeMap<Long,String> orderedChildren;
@ -122,7 +124,7 @@ public class DistributedQueue {
for (String headNode : orderedChildren.values()) {
if (headNode != null) {
try {
return zookeeper.getData(dir + "/" + headNode, null, null, true);
return new QueueEvent(dir + "/" + headNode, zookeeper.getData(dir + "/" + headNode, null, null, true), null);
} catch (KeeperException.NoNodeException e) {
// Another client removed the node first, try next
}
@ -162,17 +164,41 @@ public class DistributedQueue {
}
}
/**
* Remove the event and save the response into the other path.
*
*/
public byte[] remove(QueueEvent event) throws KeeperException,
InterruptedException {
String path = event.getId();
String responsePath = dir + "/" + response_prefix
+ path.substring(path.lastIndexOf("-") + 1);
if (zookeeper.exists(responsePath, true)) {
zookeeper.setData(responsePath, event.getBytes(), true);
}
byte[] data = zookeeper.getData(path, null, null, true);
zookeeper.delete(path, -1, true);
return data;
}
private class LatchChildWatcher implements Watcher {
Object lock = new Object();
private WatchedEvent event = null;
public LatchChildWatcher() {}
public LatchChildWatcher(Object lock) {
this.lock = lock;
}
@Override
public void process(WatchedEvent event) {
LOG.info("Watcher fired on path: " + event.getPath() + " state: "
+ event.getState() + " type " + event.getType());
synchronized (lock) {
this.event = event;
lock.notifyAll();
}
}
@ -182,6 +208,10 @@ public class DistributedQueue {
lock.wait(timeout);
}
}
public WatchedEvent getWatchedEvent() {
return event;
}
}
/**
@ -225,22 +255,51 @@ public class DistributedQueue {
*/
public boolean offer(byte[] data) throws KeeperException,
InterruptedException {
return createData(dir + "/" + prefix, data,
CreateMode.PERSISTENT_SEQUENTIAL) != null;
}
/**
* Inserts data into zookeeper.
*
* @return true if data was successfully added
*/
private String createData(String path, byte[] data, CreateMode mode)
throws KeeperException, InterruptedException {
for (;;) {
try {
zookeeper.create(dir + "/" + prefix, data, acl,
CreateMode.PERSISTENT_SEQUENTIAL, true);
return true;
return zookeeper.create(path, data, acl, mode, true);
} catch (KeeperException.NoNodeException e) {
try {
zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT, true);
} catch (KeeperException.NodeExistsException ne) {
//someone created it
// someone created it
}
}
}
}
/**
* Offer the data and wait for the response
*
*/
public QueueEvent offer(byte[] data, long timeout) throws KeeperException,
InterruptedException {
String path = createData(dir + "/" + prefix, data,
CreateMode.PERSISTENT_SEQUENTIAL);
String watchID = createData(
dir + "/" + response_prefix + path.substring(path.lastIndexOf("-") + 1),
null, CreateMode.EPHEMERAL);
Object lock = new Object();
LatchChildWatcher watcher = new LatchChildWatcher(lock);
synchronized (lock) {
if (zookeeper.exists(watchID, watcher, true) != null) {
watcher.await(timeout);
}
}
byte[] bytes = zookeeper.getData(watchID, null, null, true);
zookeeper.delete(watchID, -1, true);
return new QueueEvent(watchID, bytes, watcher.getWatchedEvent());
}
/**
@ -251,21 +310,74 @@ public class DistributedQueue {
*/
public byte[] peek() throws KeeperException, InterruptedException {
try {
return element();
return element().getBytes();
} catch (NoSuchElementException e) {
return null;
}
}
public static class QueueEvent {
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.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;
QueueEvent other = (QueueEvent) obj;
if (id == null) {
if (other.id != null) return false;
} else if (!id.equals(other.id)) return false;
return true;
}
private WatchedEvent event = null;
private String id;
private byte[] bytes;
QueueEvent(String id, byte[] bytes, WatchedEvent event) {
this.id = id;
this.bytes = bytes;
this.event = event;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setBytes(byte[] bytes) {
this.bytes = bytes;
}
public byte[] getBytes() {
return bytes;
}
public WatchedEvent getWatchedEvent() {
return event;
}
}
/**
* Returns the data at the first element of the queue, or null if the queue is
* empty.
*
* @return data at the first element of the queue, or null.
*/
public byte[] peek(boolean block) throws KeeperException, InterruptedException {
public QueueEvent peek(boolean block) throws KeeperException, InterruptedException {
if (!block) {
return peek();
return element();
}
TreeMap<Long,String> orderedChildren;
@ -286,7 +398,7 @@ public class DistributedQueue {
String path = dir + "/" + headNode;
try {
byte[] data = zookeeper.getData(path, null, null, true);
return data;
return new QueueEvent(path, data, childWatcher.getWatchedEvent());
} catch (KeeperException.NoNodeException e) {
// Another client deleted the node first.
}

View File

@ -23,6 +23,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.cloud.DistributedQueue.QueueEvent;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.cloud.ClosableThread;
@ -36,6 +38,7 @@ import org.apache.solr.common.cloud.ZooKeeperException;
import org.apache.solr.common.params.CoreAdminParams;
import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.handler.component.ShardHandler;
import org.apache.solr.handler.component.ShardRequest;
@ -94,47 +97,33 @@ public class OverseerCollectionProcessor implements Runnable, ClosableThread {
@Override
public void run() {
log.info("Process current queue of collection messages");
while (amILeader() && !isClosed) {
try {
byte[] head = workQueue.peek(true);
//if (head != null) { // should not happen since we block above
final ZkNodeProps message = ZkNodeProps.load(head);
final String operation = message.getStr(QUEUE_OPERATION);
try {
boolean success = processMessage(message, operation);
if (!success) {
// TODO: what to do on failure / partial failure
// if we fail, do we clean up then ?
SolrException.log(log,
"Collection " + operation + " of " + message.getStr("name")
+ " failed");
}
} catch(Throwable t) {
SolrException.log(log,
"Collection " + operation + " of " + message.getStr("name")
+ " failed", t);
}
//}
workQueue.poll();
} catch (KeeperException e) {
if (e.code() == KeeperException.Code.SESSIONEXPIRED
|| e.code() == KeeperException.Code.CONNECTIONLOSS) {
log.warn("Overseer cannot talk to ZK");
return;
}
SolrException.log(log, "", e);
throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "",
e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
log.info("Process current queue of collection creations");
while (amILeader() && !isClosed) {
try {
QueueEvent head = workQueue.peek(true);
final ZkNodeProps message = ZkNodeProps.load(head.getBytes());
log.info("Overseer Collection Processor: Get the message id:" + head.getId() + " message:" + message.toString());
final String operation = message.getStr(QUEUE_OPERATION);
SolrResponse response = processMessage(message, operation);
head.setBytes(SolrResponse.serializable(response));
workQueue.remove(head);
log.info("Overseer Collection Processor: Message id:" + head.getId() + " complete, response:"+ response.getResponse().toString());
} catch (KeeperException e) {
if (e.code() == KeeperException.Code.SESSIONEXPIRED
|| e.code() == KeeperException.Code.CONNECTIONLOSS) {
log.warn("Overseer cannot talk to ZK");
return;
}
SolrException.log(log, "", e);
throw new ZooKeeperException(
SolrException.ErrorCode.SERVER_ERROR, "", e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
} catch (Throwable e) {
SolrException.log(log, "", e);
}
}
}
public void close() {
@ -157,21 +146,49 @@ public class OverseerCollectionProcessor implements Runnable, ClosableThread {
return false;
}
protected boolean processMessage(ZkNodeProps message, String operation) {
if (CREATECOLLECTION.equals(operation)) {
return createCollection(zkStateReader.getClusterState(), message);
} else if (DELETECOLLECTION.equals(operation)) {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set(CoreAdminParams.ACTION, CoreAdminAction.UNLOAD.toString());
params.set(CoreAdminParams.DELETE_INSTANCE_DIR, true);
return collectionCmd(zkStateReader.getClusterState(), message, params);
} else if (RELOADCOLLECTION.equals(operation)) {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set(CoreAdminParams.ACTION, CoreAdminAction.RELOAD.toString());
return collectionCmd(zkStateReader.getClusterState(), message, params);
protected SolrResponse processMessage(ZkNodeProps message, String operation) {
NamedList results = new NamedList();
try {
if (CREATECOLLECTION.equals(operation)) {
createCollection(zkStateReader.getClusterState(), message);
} else if (DELETECOLLECTION.equals(operation)) {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set(CoreAdminParams.ACTION, CoreAdminAction.UNLOAD.toString());
params.set(CoreAdminParams.DELETE_INSTANCE_DIR, true);
collectionCmd(zkStateReader.getClusterState(), message, params);
} else if (RELOADCOLLECTION.equals(operation)) {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set(CoreAdminParams.ACTION, CoreAdminAction.RELOAD.toString());
collectionCmd(zkStateReader.getClusterState(), message, params);
} else {
throw new SolrException(ErrorCode.BAD_REQUEST, "Unknow the operation:"
+ operation);
}
int failed = 0;
ShardResponse srsp;
do {
srsp = shardHandler.takeCompletedIncludingErrors();
if (srsp != null) {
Throwable e = srsp.getException();
if (e != null) {
failed++;
log.error("Error talking to shard: " + srsp.getShard(), e);
results.add(srsp.getShard(), e);
} else {
results.add(srsp.getShard(), srsp.getSolrResponse().getResponse());
}
}
} while (srsp != null);
} catch (SolrException ex) {
SolrException.log(log, "Collection " + operation + " of " + operation
+ " failed");
results.add("Operation " + operation + " cause exception:", ex);
} finally {
return new OverseerSolrResponse(results);
}
// unknown command, toss it from our queue
return true;
}
private boolean createCollection(ClusterState clusterState, ZkNodeProps message) {

View File

@ -0,0 +1,47 @@
package org.apache.solr.cloud;
/*
* 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 org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.common.util.NamedList;
public class OverseerSolrResponse extends SolrResponse {
NamedList responseList = null;
public OverseerSolrResponse(NamedList list) {
responseList = list;
}
@Override
public long getElapsedTime() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void setResponse(NamedList<Object> rsp) {
this.responseList = rsp;
}
@Override
public NamedList<Object> getResponse() {
return responseList;
}
}

View File

@ -21,10 +21,12 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.request.CoreAdminRequest;
import org.apache.solr.client.solrj.request.CoreAdminRequest.RequestSyncShard;
import org.apache.solr.cloud.DistributedQueue.QueueEvent;
import org.apache.solr.cloud.Overseer;
import org.apache.solr.cloud.OverseerCollectionProcessor;
import org.apache.solr.common.SolrException;
@ -127,7 +129,35 @@ public class CollectionsHandler extends RequestHandlerBase {
rsp.setHttpCaching(false);
}
public static long DEFAULT_ZK_TIMEOUT = 60*1000;
private void handleResponse(String operation, ZkNodeProps m,
SolrQueryResponse rsp) throws KeeperException, InterruptedException {
long time = System.currentTimeMillis();
QueueEvent event = coreContainer.getZkController()
.getOverseerCollectionQueue()
.offer(ZkStateReader.toJSON(m), DEFAULT_ZK_TIMEOUT);
if (event.getBytes() != null) {
SolrResponse response = SolrResponse.deserialize(event.getBytes());
rsp.getValues().addAll(response.getResponse());
} else {
if (System.currentTimeMillis() - time >= DEFAULT_ZK_TIMEOUT) {
throw new SolrException(ErrorCode.SERVER_ERROR, operation
+ " the collection time out:" + DEFAULT_ZK_TIMEOUT / 1000 + "s");
} else if (event.getWatchedEvent() != null) {
throw new SolrException(ErrorCode.SERVER_ERROR, operation
+ " the collection error [Watcher fired on path: "
+ event.getWatchedEvent().getPath() + " state: "
+ event.getWatchedEvent().getState() + " type "
+ event.getWatchedEvent().getType() + "]");
} else {
throw new SolrException(ErrorCode.SERVER_ERROR, operation
+ " the collection unkown case");
}
}
}
private void handleReloadAction(SolrQueryRequest req, SolrQueryResponse rsp) throws KeeperException, InterruptedException {
log.info("Reloading Collection : " + req.getParamString());
String name = req.getParams().required().get("name");
@ -135,8 +165,7 @@ public class CollectionsHandler extends RequestHandlerBase {
ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION,
OverseerCollectionProcessor.RELOADCOLLECTION, "name", name);
// TODO: what if you want to block until the collection is available?
coreContainer.getZkController().getOverseerCollectionQueue().offer(ZkStateReader.toJSON(m));
handleResponse(OverseerCollectionProcessor.RELOADCOLLECTION, m, rsp);
}
private void handleSyncShardAction(SolrQueryRequest req, SolrQueryResponse rsp) throws KeeperException, InterruptedException, SolrServerException, IOException {
@ -168,8 +197,7 @@ public class CollectionsHandler extends RequestHandlerBase {
ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION,
OverseerCollectionProcessor.DELETECOLLECTION, "name", name);
// TODO: what if you want to block until the collection is available?
coreContainer.getZkController().getOverseerCollectionQueue().offer(ZkStateReader.toJSON(m));
handleResponse(OverseerCollectionProcessor.DELETECOLLECTION, m, rsp);
}
@ -208,8 +236,7 @@ public class CollectionsHandler extends RequestHandlerBase {
ZkNodeProps m = new ZkNodeProps(props);
// TODO: what if you want to block until the collection is available?
coreContainer.getZkController().getOverseerCollectionQueue().offer(ZkStateReader.toJSON(m));
handleResponse(OverseerCollectionProcessor.CREATECOLLECTION, m, rsp);
}
public static ModifiableSolrParams params(String... params) {

View File

@ -29,8 +29,6 @@ import org.apache.lucene.document.FieldType.NumericType;
import org.apache.lucene.document.FloatField;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
import org.apache.lucene.index.GeneralField;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.StorableField;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.valuesource.DoubleFieldSource;
@ -48,7 +46,6 @@ import org.apache.solr.analysis.TrieTokenizerFactory;
import org.apache.solr.common.SolrException;
import org.apache.solr.response.TextResponseWriter;
import org.apache.solr.search.QParser;
import org.apache.solr.search.function.*;
/**
* Provides field types to support for Lucene's {@link
@ -311,19 +308,19 @@ public class TrieField extends PrimitiveFieldType {
String s = val.toString();
switch (type) {
case INTEGER:
NumericUtils.intToPrefixCoded(Integer.parseInt(s), 0, result);
NumericUtils.intToPrefixCodedBytes(Integer.parseInt(s), 0, result);
break;
case FLOAT:
NumericUtils.intToPrefixCoded(NumericUtils.floatToSortableInt(Float.parseFloat(s)), 0, result);
NumericUtils.intToPrefixCodedBytes(NumericUtils.floatToSortableInt(Float.parseFloat(s)), 0, result);
break;
case LONG:
NumericUtils.longToPrefixCoded(Long.parseLong(s), 0, result);
NumericUtils.longToPrefixCodedBytes(Long.parseLong(s), 0, result);
break;
case DOUBLE:
NumericUtils.longToPrefixCoded(NumericUtils.doubleToSortableLong(Double.parseDouble(s)), 0, result);
NumericUtils.longToPrefixCodedBytes(NumericUtils.doubleToSortableLong(Double.parseDouble(s)), 0, result);
break;
case DATE:
NumericUtils.longToPrefixCoded(dateField.parseMath(null, s).getTime(), 0, result);
NumericUtils.longToPrefixCodedBytes(dateField.parseMath(null, s).getTime(), 0, result);
break;
default:
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + type);
@ -419,17 +416,17 @@ public class TrieField extends PrimitiveFieldType {
if (val != null) {
switch (type) {
case INTEGER:
NumericUtils.intToPrefixCoded(val.intValue(), 0, bytes);
NumericUtils.intToPrefixCodedBytes(val.intValue(), 0, bytes);
break;
case FLOAT:
NumericUtils.intToPrefixCoded(NumericUtils.floatToSortableInt(val.floatValue()), 0, bytes);
NumericUtils.intToPrefixCodedBytes(NumericUtils.floatToSortableInt(val.floatValue()), 0, bytes);
break;
case LONG: //fallthrough!
case DATE:
NumericUtils.longToPrefixCoded(val.longValue(), 0, bytes);
NumericUtils.longToPrefixCodedBytes(val.longValue(), 0, bytes);
break;
case DOUBLE:
NumericUtils.longToPrefixCoded(NumericUtils.doubleToSortableLong(val.doubleValue()), 0, bytes);
NumericUtils.longToPrefixCodedBytes(NumericUtils.doubleToSortableLong(val.doubleValue()), 0, bytes);
break;
default:
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + f.name());
@ -441,7 +438,7 @@ public class TrieField extends PrimitiveFieldType {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Invalid field contents: "+f.name());
switch (type) {
case INTEGER:
NumericUtils.intToPrefixCoded(toInt(bytesRef.bytes, bytesRef.offset), 0, bytes);
NumericUtils.intToPrefixCodedBytes(toInt(bytesRef.bytes, bytesRef.offset), 0, bytes);
break;
case FLOAT: {
// WARNING: Code Duplication! Keep in sync with o.a.l.util.NumericUtils!
@ -449,12 +446,12 @@ public class TrieField extends PrimitiveFieldType {
// code in next 2 lines is identical to: int v = NumericUtils.floatToSortableInt(Float.intBitsToFloat(toInt(arr)));
int v = toInt(bytesRef.bytes, bytesRef.offset);
if (v<0) v ^= 0x7fffffff;
NumericUtils.intToPrefixCoded(v, 0, bytes);
NumericUtils.intToPrefixCodedBytes(v, 0, bytes);
break;
}
case LONG: //fallthrough!
case DATE:
NumericUtils.longToPrefixCoded(toLong(bytesRef.bytes, bytesRef.offset), 0, bytes);
NumericUtils.longToPrefixCodedBytes(toLong(bytesRef.bytes, bytesRef.offset), 0, bytes);
break;
case DOUBLE: {
// WARNING: Code Duplication! Keep in sync with o.a.l.util.NumericUtils!
@ -462,7 +459,7 @@ public class TrieField extends PrimitiveFieldType {
// code in next 2 lines is identical to: long v = NumericUtils.doubleToSortableLong(Double.longBitsToDouble(toLong(arr)));
long v = toLong(bytesRef.bytes, bytesRef.offset);
if (v<0) v ^= 0x7fffffffffffffffL;
NumericUtils.longToPrefixCoded(v, 0, bytes);
NumericUtils.longToPrefixCodedBytes(v, 0, bytes);
break;
}
default:

View File

@ -917,10 +917,11 @@ public class UpdateLog implements PluginInfoInitialized {
reader = oldLog.getReverseReader();
while (numUpdates < numRecordsToKeep) {
Object o = reader.next();
if (o==null) break;
Object o = null;
try {
o = reader.next();
if (o==null) break;
// should currently be a List<Oper,Ver,Doc/Id>
List entry = (List)o;

View File

@ -19,10 +19,11 @@ package org.apache.solr.cloud;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.reset;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.reset;
import static org.easymock.EasyMock.verify;
import java.util.ArrayList;
@ -36,6 +37,8 @@ import java.util.Queue;
import java.util.Set;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.cloud.DistributedQueue.QueueEvent;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.cloud.ZkNodeProps;
@ -43,11 +46,13 @@ import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.CoreAdminParams;
import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.handler.component.ShardHandler;
import org.apache.solr.handler.component.ShardRequest;
import org.apache.solr.handler.component.ShardResponse;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.junit.After;
@ -71,12 +76,12 @@ public class OverseerCollectionProcessorTest extends SolrTestCaseJ4 {
private OverseerCollectionProcessorToBeTested underTest;
private Thread thread;
private Queue<byte[]> queue = new BlockingArrayQueue<byte[]>();
private Queue<QueueEvent> queue = new BlockingArrayQueue<QueueEvent>();
private class OverseerCollectionProcessorToBeTested extends
OverseerCollectionProcessor {
private boolean lastProcessMessageResult = true;
private SolrResponse lastProcessMessageResult;
public OverseerCollectionProcessorToBeTested(ZkStateReader zkStateReader,
String myId, ShardHandler shardHandler, String adminPath,
@ -85,7 +90,7 @@ public class OverseerCollectionProcessorTest extends SolrTestCaseJ4 {
}
@Override
protected boolean processMessage(ZkNodeProps message, String operation) {
protected SolrResponse processMessage(ZkNodeProps message, String operation) {
lastProcessMessageResult = super.processMessage(message, operation);
return lastProcessMessageResult;
}
@ -147,11 +152,12 @@ public class OverseerCollectionProcessorTest extends SolrTestCaseJ4 {
}
}).anyTimes();
workQueueMock.remove();
workQueueMock.remove(anyObject(QueueEvent.class));
expectLastCall().andAnswer(new IAnswer<Object>() {
@Override
public Object answer() throws Throwable {
return queue.poll();
queue.remove((QueueEvent)EasyMock.getCurrentArguments()[0]);
return null;
}
}).anyTimes();
@ -273,7 +279,8 @@ public class OverseerCollectionProcessorTest extends SolrTestCaseJ4 {
OverseerCollectionProcessor.MAX_SHARDS_PER_NODE,
maxShardsPerNode.toString());
}
queue.add(ZkStateReader.toJSON(props));
QueueEvent qe = new QueueEvent("id", ZkStateReader.toJSON(props), null);
queue.add(qe);
}
protected void verifySubmitCaptures(List<SubmitCapture> submitCaptures,
@ -443,7 +450,9 @@ public class OverseerCollectionProcessorTest extends SolrTestCaseJ4 {
waitForEmptyQueue(10000);
assertEquals(collectionExceptedToBeCreated, underTest.lastProcessMessageResult);
if (collectionExceptedToBeCreated) {
assertNotNull(underTest.lastProcessMessageResult.getResponse().toString(), underTest.lastProcessMessageResult);
}
verify(shardHandlerMock);
if (collectionExceptedToBeCreated) {

View File

@ -25,7 +25,10 @@ import org.apache.solr.common.params.StatsParams;
import org.apache.solr.common.params.TermsParams;
import org.apache.solr.common.util.DateUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
@ -44,6 +47,9 @@ public class SolrQuery extends ModifiableSolrParams
return (this == asc) ? desc : asc;
}
}
/** Maintains a map of current sorts */
private List<SortClause> sortClauses;
public SolrQuery() {
super();
@ -529,38 +535,230 @@ public class SolrQuery extends ModifiableSolrParams
return this.get(HighlightParams.SIMPLE_POST, "");
}
/**
* Replaces the sort string with a single sort field.
* @deprecated Use {@link #setSort(SortClause)} instead, which is part
* of an api handling a wider range of sort specifications.
*/
@Deprecated
public SolrQuery setSortField(String field, ORDER order) {
this.remove(CommonParams.SORT);
addValueToParam(CommonParams.SORT, toSortString(field, order));
return this;
}
/**
* Adds a sort field to the end of the sort string.
* @deprecated Use {@link #addSort(SortClause)} instead, which is part
* of an api handling a wider range of sort specifications.
*/
@Deprecated
public SolrQuery addSortField(String field, ORDER order) {
return addValueToParam(CommonParams.SORT, toSortString(field, order));
}
/**
* Removes a sort field to the end of the sort string.
* @deprecated Use {@link #removeSort(SortClause)} instead, which is part
* of an api handling a wider range of sort specifications.
*/
@Deprecated
public SolrQuery removeSortField(String field, ORDER order) {
String s = this.get(CommonParams.SORT);
String removeSort = toSortString(field, order);
if (s != null) {
String[] sorts = s.split(",");
s = join(sorts, ", ", removeSort);
String[] sorts = getSortFields();
if (sorts != null) {
String removeSort = toSortString(field, order);
String s = join(sorts, ",", removeSort);
if (s.length()==0) s=null;
this.set(CommonParams.SORT, s);
}
return this;
}
/**
* Gets an array of sort specifications.
* @deprecated Use {@link #getSorts()} instead, which is part
* of an api handling a wider range of sort specifications.
*/
@Deprecated
public String[] getSortFields() {
String s = getSortField();
if (s==null) return null;
return s.split(",");
return s.trim().split(", *");
}
/**
* Gets the raw sort field, as it will be sent to Solr.
* <p>
* The returned sort field will always contain a serialized version
* of the sort string built using {@link #setSort(SortClause)},
* {@link #addSort(SortClause)}, {@link #addOrUpdateSort(SortClause)},
* {@link #removeSort(SortClause)}, {@link #clearSorts()} and
* {@link #setSorts(List)}.
*/
public String getSortField() {
return this.get(CommonParams.SORT);
}
/**
* Clears current sort information.
*
* @return the modified SolrQuery object, for easy chaining
* @since 4.2
*/
public SolrQuery clearSorts() {
sortClauses = null;
serializeSorts();
return this;
}
/**
* Replaces the current sort information.
*
* @return the modified SolrQuery object, for easy chaining
* @since 4.2
*/
public SolrQuery setSorts(List<SortClause> value) {
sortClauses = new ArrayList<SortClause>(value);
serializeSorts();
return this;
}
/**
* Gets an a list of current sort clauses.
*
* @return an immutable list of current sort clauses
* @since 4.2
*/
public List<SortClause> getSorts() {
if (sortClauses == null) return Collections.emptyList();
else return Collections.unmodifiableList(sortClauses);
}
/**
* Replaces the current sort information with a single sort clause
*
* @return the modified SolrQuery object, for easy chaining
* @since 4.2
*/
public SolrQuery setSort(String field, ORDER order) {
return setSort(new SortClause(field, order));
}
/**
* Replaces the current sort information with a single sort clause
*
* @return the modified SolrQuery object, for easy chaining
* @since 4.2
*/
public SolrQuery setSort(SortClause sortClause) {
clearSorts();
return addSort(sortClause);
}
/**
* Adds a single sort clause to the end of the current sort information.
*
* @return the modified SolrQuery object, for easy chaining
* @since 4.2
*/
public SolrQuery addSort(String field, ORDER order) {
return addSort(new SortClause(field, order));
}
/**
* Adds a single sort clause to the end of the query.
*
* @return the modified SolrQuery object, for easy chaining
* @since 4.2
*/
public SolrQuery addSort(SortClause sortClause) {
if (sortClauses == null) sortClauses = new ArrayList<SortClause>();
sortClauses.add(sortClause);
serializeSorts();
return this;
}
/**
* Updates or adds a single sort clause to the query.
* If the field is already used for sorting, the order
* of the existing field is modified; otherwise, it is
* added to the end.
* <p>
* @return the modified SolrQuery object, for easy chaining
* @since 4.2
*/
public SolrQuery addOrUpdateSort(String field, ORDER order) {
return addOrUpdateSort(new SortClause(field, order));
}
/**
* Updates or adds a single sort field specification to the current sort
* information. If the sort field already exist in the sort information map,
* it's position is unchanged and the sort order is set; if it does not exist,
* it is appended at the end with the specified order..
*
* @return the modified SolrQuery object, for easy chaining
* @since 4.2
*/
public SolrQuery addOrUpdateSort(SortClause sortClause) {
if (sortClauses != null) {
for (int index=0 ; index<sortClauses.size() ; index++) {
SortClause existing = sortClauses.get(index);
if (existing.getItem().equals(sortClause.getItem())) {
sortClauses.set(index, sortClause);
serializeSorts();
return this;
}
}
}
return addSort(sortClause);
}
/**
* Removes a single sort field from the current sort information.
*
* @return the modified SolrQuery object, for easy chaining
* @since 4.2
*/
public SolrQuery removeSort(SortClause sortClause) {
return removeSort(sortClause.getItem());
}
/**
* Removes a single sort field from the current sort information.
*
* @return the modified SolrQuery object, for easy chaining
* @since 4.2
*/
public SolrQuery removeSort(String itemName) {
if (sortClauses != null) {
for (SortClause existing : sortClauses) {
if (existing.getItem().equals(itemName)) {
sortClauses.remove(existing);
if (sortClauses.isEmpty()) sortClauses = null;
serializeSorts();
break;
}
}
}
return this;
}
private void serializeSorts() {
if (sortClauses == null || sortClauses.isEmpty()) {
remove(CommonParams.SORT);
} else {
StringBuilder sb = new StringBuilder();
for (SortClause sortClause : sortClauses) {
if (sb.length() > 0) sb.append(",");
sb.append(sortClause.getItem());
sb.append(" ");
sb.append(sortClause.getOrder());
}
set(CommonParams.SORT, sb.toString());
}
}
public void setGetFieldStatistics( boolean v )
{
this.set( StatsParams.STATS, v );
@ -823,13 +1021,126 @@ public class SolrQuery extends ModifiableSolrParams
private String join(String[] vals, String sep, String removeVal) {
StringBuilder sb = new StringBuilder();
for (int i=0; i<vals.length; i++) {
if (removeVal==null || !vals[i].equals(removeVal)) {
sb.append(vals[i]);
if (i<vals.length-1) {
if (!vals[i].equals(removeVal)) {
if (sb.length() > 0) {
sb.append(sep);
}
sb.append(vals[i]);
}
}
return sb.toString().trim();
}
/**
* A single sort clause, encapsulating what to sort and the sort order.
* <p>
* The item specified can be "anything sortable" by solr; some examples
* include a simple field name, the constant string {@code score}, and functions
* such as {@code sum(x_f, y_f)}.
* <p>
* A SortClause can be created through different mechanisms:
* <PRE><code>
* new SortClause("product", SolrQuery.ORDER.asc);
* new SortClause("product", "asc");
* SortClause.asc("product");
* SortClause.desc("product");
* </code></PRE>
*/
public static class SortClause implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private final String item;
private final ORDER order;
/**
* Creates a SortClause based on item and order
* @param item item to sort on
* @param order direction to sort
*/
public SortClause(String item, ORDER order) {
this.item = item;
this.order = order;
}
/**
* Creates a SortClause based on item and order
* @param item item to sort on
* @param order string value for direction to sort
*/
public SortClause(String item, String order) {
this(item, ORDER.valueOf(order));
}
/**
* Creates an ascending SortClause for an item
* @param item item to sort on
*/
public static SortClause create (String item, ORDER order) {
return new SortClause(item, order);
}
/**
* Creates a SortClause based on item and order
* @param item item to sort on
* @param order string value for direction to sort
*/
public static SortClause create(String item, String order) {
return new SortClause(item, ORDER.valueOf(order));
}
/**
* Creates an ascending SortClause for an item
* @param item item to sort on
*/
public static SortClause asc (String item) {
return new SortClause(item, ORDER.asc);
}
/**
* Creates a decending SortClause for an item
* @param item item to sort on
*/
public static SortClause desc (String item) {
return new SortClause(item, ORDER.desc);
}
/**
* Gets the item to sort, typically a function or a fieldname
* @return item to sort
*/
public String getItem() {
return item;
}
/**
* Gets the order to sort
* @return order to sort
*/
public ORDER getOrder() {
return order;
}
public boolean equals(Object other){
if (this == other) return true;
if (!(other instanceof SortClause)) return false;
final SortClause that = (SortClause) other;
return this.getItem().equals(that.getItem()) && this.getOrder().equals(that.getOrder());
}
public int hashCode(){
return this.getItem().hashCode();
}
/**
* Gets a human readable description of the sort clause.
* <p>
* The returned string is not suitable for passing to Solr,
* but may be useful in debug output and the like.
* @return a description of the current sort clause
*/
public String toString() {
return "[" + getClass().getSimpleName() + ": item=" + getItem() + "; order=" + getOrder() + "]";
}
}
}

View File

@ -17,19 +17,47 @@
package org.apache.solr.client.solrj;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.util.NamedList;
/**
*
*
*
* @since solr 1.3
*/
public abstract class SolrResponse implements Serializable
{
public abstract class SolrResponse implements Serializable {
public abstract long getElapsedTime();
public abstract void setResponse( NamedList<Object> rsp );
public abstract void setResponse(NamedList<Object> rsp);
public abstract NamedList<Object> getResponse();
public static byte[] serializable(SolrResponse response) {
try {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(byteStream);
outputStream.writeObject(response);
return byteStream.toByteArray();
} catch (Exception e) {
throw new SolrException(ErrorCode.SERVER_ERROR, e);
}
}
public static SolrResponse deserialize(byte[] bytes) {
try {
ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
ObjectInputStream inputStream = new ObjectInputStream(byteStream);
return (SolrResponse) inputStream.readObject();
} catch (Exception e) {
throw new SolrException(ErrorCode.SERVER_ERROR, e);
}
}
}

View File

@ -108,7 +108,13 @@ public class SolrDocument implements Map<String,Object>, Iterable<Map.Entry<Stri
/**
* This will add a field to the document. If fields already exist with this
* name it will append value to the collection. If the value is Collection,
* each value will be added independently.
* each value will be added independently.
*
* The class type of value and the name parameter should match schema.xml.
* schema.xml can be found in conf directory under the solr home by default.
*
* @param name Name of the field, should match one of the field names defined under "fields" tag in schema.xml.
* @param value Value of the field, should be of same class type as defined by "type" attribute of the corresponding field in schema.xml.
*/
@SuppressWarnings("unchecked")
public void addField(String name, Object value)

View File

@ -63,9 +63,12 @@ public class SolrInputDocument implements Map<String,SolrInputField>, Iterable<S
/**
* Add a field with implied null value for boost.
*
* The class type of value and the name parameter should match schema.xml.
* schema.xml can be found in conf directory under the solr home by default.
*
* @param name Name of the field, should match one of the field names defined under "fields" tag in schema.xml.
* @param value Value of the field, should be of same class type as defined by "type" attribute of the corresponding field in schema.xml.
* @see #addField(String, Object, float)
* @param name name of the field to add
* @param value value of the field
*/
public void addField(String name, Object value)
{
@ -132,8 +135,11 @@ public class SolrInputDocument implements Map<String,SolrInputField>, Iterable<S
* field, with the new boost. If the value is a collection, then each of its
* values will be added to the field.
*
* @param name Name of the field to add
* @param value Value of the field
* The class type of value and the name parameter should match schema.xml.
* schema.xml can be found in conf directory under the solr home by default.
*
* @param name Name of the field, should match one of the field names defined under "fields" tag in schema.xml.
* @param value Value of the field, should be of same class type as defined by "type" attribute of the corresponding field in schema.xml.
* @param boost Boost value for the field
*/
public void addField(String name, Object value, float boost )

View File

@ -18,11 +18,17 @@
package org.apache.solr.client.solrj;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.client.solrj.SolrQuery.SortClause;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.FacetParams;
import junit.framework.Assert;
import org.apache.solr.common.util.DateUtil;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
@ -98,6 +104,169 @@ public class SolrQueryTest extends LuceneTestCase {
// System.out.println(q);
}
/*
* Verifies that the old (deprecated) sort methods
* allows mix-and-match between the raw field and
* the itemized apis.
*/
public void testSortFieldRawStringAndMethods() {
SolrQuery q = new SolrQuery("dog");
q.set("sort", "price asc,date desc,qty desc");
q.removeSortField("date", SolrQuery.ORDER.desc);
Assert.assertEquals(2, q.getSortFields().length);
q.set("sort", "price asc, date desc, qty desc");
q.removeSortField("date", SolrQuery.ORDER.desc);
Assert.assertEquals(2, q.getSortFields().length);
}
/*
* Verifies that you can use removeSortField() twice, which
* did not work in 4.0
*/
public void testSortFieldRemoveAfterRemove() {
SolrQuery q = new SolrQuery("dog");
q.addSortField("price", SolrQuery.ORDER.asc);
q.addSortField("date", SolrQuery.ORDER.desc);
q.addSortField("qty", SolrQuery.ORDER.desc);
q.removeSortField("date", SolrQuery.ORDER.desc);
Assert.assertEquals(2, q.getSortFields().length);
q.removeSortField("qty", SolrQuery.ORDER.desc);
Assert.assertEquals(1, q.getSortFields().length);
}
/*
* Verifies that you can remove the last sort field, which
* did not work in 4.0
*/
public void testSortFieldRemoveLast() {
SolrQuery q = new SolrQuery("dog");
q.addSortField("date", SolrQuery.ORDER.desc);
q.addSortField("qty", SolrQuery.ORDER.desc);
q.removeSortField("qty", SolrQuery.ORDER.desc);
Assert.assertEquals("date desc", q.getSortField());
}
/*
* Verifies that getSort() returns an immutable map,
* for both empty and non-empty situations
*/
public void testGetSortImmutable() {
SolrQuery q = new SolrQuery("dog");
try {
q.getSorts().add(new SortClause("price", SolrQuery.ORDER.asc));
fail("The returned (empty) map should be immutable; put() should fail!");
} catch (UnsupportedOperationException uoe) {
// pass
}
q.addSort("qty", SolrQuery.ORDER.desc);
try {
q.getSorts().add(new SortClause("price", SolrQuery.ORDER.asc));
fail("The returned (non-empty) map should be immutable; put() should fail!");
} catch (UnsupportedOperationException uoe) {
// pass
}
// Should work even when setSorts passes an Immutable List
q.setSorts(Arrays.asList(new SortClause("price", SolrQuery.ORDER.asc)));
q.addSort(new SortClause("price", SolrQuery.ORDER.asc));
}
public void testSortClause() {
new SolrQuery.SortClause("rating", SolrQuery.ORDER.desc);
new SolrQuery.SortClause("rating", SolrQuery.ORDER.valueOf("desc"));
new SolrQuery.SortClause("rating", SolrQuery.ORDER.valueOf("desc"));
SolrQuery.SortClause.create("rating", SolrQuery.ORDER.desc);
SolrQuery.SortClause.create("rating", SolrQuery.ORDER.desc);
SolrQuery.SortClause.create("rating", SolrQuery.ORDER.desc);
SolrQuery.SortClause sc1a = SolrQuery.SortClause.asc("sc1");
SolrQuery.SortClause sc1b = SolrQuery.SortClause.asc("sc1");
Assert.assertEquals(sc1a, sc1b);
Assert.assertEquals(sc1a.hashCode(), sc1b.hashCode());
SolrQuery.SortClause sc2a = SolrQuery.SortClause.asc("sc2");
SolrQuery.SortClause sc2b = SolrQuery.SortClause.desc("sc2");
Assert.assertFalse(sc2a.equals(sc2b));
SolrQuery.SortClause sc3a = SolrQuery.SortClause.asc("sc2");
SolrQuery.SortClause sc3b = SolrQuery.SortClause.asc("not sc2");
Assert.assertFalse(sc3a.equals(sc3b));
}
/*
* Verifies the symbolic sort operations
*/
public void testSort() throws IOException {
SolrQuery q = new SolrQuery("dog");
// Simple adds
q.addSort("price", SolrQuery.ORDER.asc);
q.addSort("date", SolrQuery.ORDER.desc);
q.addSort("qty", SolrQuery.ORDER.desc);
Assert.assertEquals(3, q.getSorts().size());
Assert.assertEquals("price asc,date desc,qty desc", q.get(CommonParams.SORT));
// Remove one (middle)
q.removeSort("date");
Assert.assertEquals(2, q.getSorts().size());
Assert.assertEquals("price asc,qty desc", q.get(CommonParams.SORT));
// Remove remaining (last, first)
q.removeSort("price");
q.removeSort("qty");
Assert.assertTrue(q.getSorts().isEmpty());
Assert.assertNull(q.get(CommonParams.SORT));
// Clear sort
q.addSort("price", SolrQuery.ORDER.asc);
q.clearSorts();
Assert.assertTrue(q.getSorts().isEmpty());
Assert.assertNull(q.get(CommonParams.SORT));
// Add vs update
q.clearSorts();
q.addSort("1", SolrQuery.ORDER.asc);
q.addSort("2", SolrQuery.ORDER.asc);
q.addSort("3", SolrQuery.ORDER.asc);
q.addOrUpdateSort("2", SolrQuery.ORDER.desc);
q.addOrUpdateSort("4", SolrQuery.ORDER.desc);
Assert.assertEquals("1 asc,2 desc,3 asc,4 desc", q.get(CommonParams.SORT));
// Using SortClause
q.clearSorts();
q.addSort(new SortClause("1", SolrQuery.ORDER.asc));
q.addSort(new SortClause("2", SolrQuery.ORDER.asc));
q.addSort(new SortClause("3", SolrQuery.ORDER.asc));
q.addOrUpdateSort(SortClause.desc("2"));
q.addOrUpdateSort(SortClause.asc("4"));
Assert.assertEquals("1 asc,2 desc,3 asc,4 asc", q.get(CommonParams.SORT));
q.setSort(SortClause.asc("A"));
q.addSort(SortClause.asc("B"));
q.addSort(SortClause.asc("C"));
q.addSort(SortClause.asc("D"));
Assert.assertEquals("A asc,B asc,C asc,D asc", q.get(CommonParams.SORT));
// removeSort should ignore the ORDER
q.setSort(SortClause.asc("A"));
q.addSort(SortClause.asc("B"));
q.addSort(SortClause.asc("C"));
q.addSort(SortClause.asc("D"));
q.removeSort("A");
q.removeSort(SortClause.asc("C"));
q.removeSort(SortClause.desc("B"));
Assert.assertEquals("D asc", q.get(CommonParams.SORT));
// Verify that a query containing a SortClause is serializable
q.clearSorts();
q.addSort("1", SolrQuery.ORDER.asc);
ObjectOutputStream out = new ObjectOutputStream(new ByteArrayOutputStream());
out.writeObject(q);
out.close();
}
public void testFacetSort() {
SolrQuery q = new SolrQuery("dog");
assertEquals("count", q.getFacetSortString());

View File

@ -390,7 +390,8 @@
color: #333;
}
#content #schema-browser #data #field .topterms-holder
#content #schema-browser #data #field .topterms-holder,
#content #schema-browser #data #field .histogram-holder
{
border-left: 1px solid #f0f0f0;
display: none;
@ -448,12 +449,12 @@
margin-bottom: 5px;
}
/* possible overwrite with inline style */
#content #schema-browser .topterms-holder li p
{
background-color: #999;
color: #fff;
float: left;
width: 25px;
}
#content #schema-browser .topterms-holder li p span
@ -463,6 +464,7 @@
text-align: right;
}
/* possible overwrite with inline style */
#content #schema-browser .topterms-holder li ul
{
margin-left: 30px;
@ -492,51 +494,65 @@
background-color: #c0c0c0;
}
#content #schema-browser #data #field .histogram-holder
#content #schema-browser #data #field .histogram-holder ul
{
border-left: 1px solid #f0f0f0;
display: none;
float: left;
padding-left: 20px;
padding-right: 20px;
margin-left: 25px;
}
#content #schema-browser #data #field .histogram-holder .histogram
#content #schema-browser #data #field .histogram-holder li
{
height: 150px;
margin-bottom: 2px;
position: relative;
width: 150px;
}
#content #schema-browser #data #field .histogram-holder .histogram.single canvas
{
background-color: #c0c0c0;
}
#content #schema-browser #data #field .histogram-holder dt,
#content #schema-browser #data #field .histogram-holder dd
{
float: left;
font-size: 10px;
text-align: center;
}
#content #schema-browser #data #field .histogram-holder span
#content #schema-browser #data #field .histogram-holder li.odd
{
background-color: #f0f0f0;
}
#content #schema-browser #data #field .histogram-holder li dl,
#content #schema-browser #data #field .histogram-holder li dt
{
padding-top: 1px;
padding-bottom: 1px;
}
#content #schema-browser #data #field .histogram-holder li dl
{
background-color: #c0c0c0;
min-width: 1px;
}
#content #schema-browser #data #field .histogram-holder li dt
{
color: #a0a0a0;
position: absolute;
overflow: hidden;
left: -25px;
top: 0px;
}
#content #schema-browser #data #field .histogram-holder li dt span
{
display: block;
width: 20px;
padding-right: 4px;
text-align: right;
}
#content #schema-browser #data #field .histogram-holder dt
#content #schema-browser #data #field .histogram-holder li dd
{
padding-right: 1px;
clear: left;
float: left;
margin-left: 2px;
}
#content #schema-browser #data #field .histogram-holder dd
#content #schema-browser #data #field .histogram-holder li:hover dl
{
padding-right: 3px;
background-color: #b0b0b0;
}
#content #schema-browser #data #field .histogram-holder dd span
#content #schema-browser #data #field .histogram-holder li:hover dt
{
width: 25px;
}
color: #333;
}

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,6 @@ require
'lib/order!lib/jquery.form',
'lib/order!lib/jquery.jstree',
'lib/order!lib/jquery.sammy',
'lib/order!lib/jquery.sparkline',
'lib/order!lib/jquery.timeago',
'lib/order!lib/jquery.blockUI',
'lib/order!lib/highlight',

View File

@ -468,6 +468,11 @@ var solr_admin = function( app_config )
return json_str;
};
this.format_number = function format_number( number )
{
return ( number || 0 ).toString().replace( /\B(?=(\d{3})+(?!\d))/g, ' ' );
};
};
var app = new solr_admin( app_config );

View File

@ -440,11 +440,6 @@ sammy.get
var messages_count = 0;
for( var key in messages ) { messages_count++; }
var format_number = function format_number( number )
{
return ( number || 0 ).toString().replace( /\B(?=(\d{3})+(?!\d))/g, '\'' );
};
function dataimport_compute_details( response, details_element, elapsed_seconds )
{
details_element
@ -464,10 +459,10 @@ sammy.get
{
var value = parseInt( response.statusMessages[document_config[key]], 10 );
var detail = '<abbr title="' + document_config[key].esc() + '">' + key.esc() + '</abbr>: ' + format_number( value ).esc();
var detail = '<abbr title="' + document_config[key].esc() + '">' + key.esc() + '</abbr>: ' + app.format_number( value ).esc();
if( elapsed_seconds && 'skipped' !== key.toLowerCase() )
{
detail += ' <span>(' + format_number( Math.round( value / elapsed_seconds ) ).esc() + '/s)</span>'
detail += ' <span>(' + app.format_number( Math.round( value / elapsed_seconds ) ).esc() + '/s)</span>'
}
document_details.push( detail );
@ -523,7 +518,7 @@ sammy.get
/\d{4,}/g,
function( match, position, string )
{
return format_number( parseInt( match, 10 ) );
return app.format_number( parseInt( match, 10 ) );
}
);

View File

@ -66,9 +66,7 @@ var load_terminfo = function( trigger_element, core_basepath, field, data_elemen
},
success : function( response, text_status, xhr )
{
$( 'span', trigger_element )
.removeClass( 'loader' );
var additional_styles = [];
var field_data = response.fields[field];
if( !field_data || !( field_data.topTerms && field_data.histogram ) )
@ -79,6 +77,11 @@ var load_terminfo = function( trigger_element, core_basepath, field, data_elemen
return false;
}
var get_width = function get_width()
{
return $( this ).width();
}
var topterms_holder_element = $( '.topterms-holder', data_element );
var histogram_holder_element = $( '.histogram-holder', data_element );
@ -111,7 +114,7 @@ var load_terminfo = function( trigger_element, core_basepath, field, data_elemen
topterms_frq_last = topterms[i+1];
topterms_content += '<li class="clearfix">'
+ '<p><span>' + topterms_frq_last.esc() + '</span></p>' + "\n"
+ '<p><span>' + app.format_number( topterms_frq_last ) + '</span></p>' + "\n"
+ '<ul>' + "\n";
}
@ -129,6 +132,13 @@ var load_terminfo = function( trigger_element, core_basepath, field, data_elemen
topterms_table_element
.html( topterms_content );
var max_width = 10 + Math.max.apply( Math, $( 'p', topterms_table_element ).map( get_width ).get() );
additional_styles.push
(
topterms_table_element.selector + ' p { width: ' + max_width + 'px !important; }' + "\n" +
topterms_table_element.selector + ' ul { margin-left: ' + ( max_width + 5 ) + 'px !important; }'
);
topterms_count_element
.val( topterms_count );
@ -152,52 +162,57 @@ var load_terminfo = function( trigger_element, core_basepath, field, data_elemen
histogram_holder_element
.show();
var histogram_element = $( '.histogram', histogram_holder_element );
var histogram_values = luke_array_to_hash( field_data.histogram );
var histogram_legend = '';
histogram_holder_element
.show();
var histogram_entries = [];
var histogram_max = null;
for( var key in histogram_values )
{
histogram_max = Math.max( histogram_max, histogram_values[key] );
}
for( var key in histogram_values )
{
histogram_legend += '<dt><span>' + key + '</span></dt>' + "\n" +
'<dd title="' + key + '">' +
'<span>' + histogram_values[key] + '</span>' +
'</dd>' + "\n";
histogram_entries.push
(
'<li>' + "\n" +
' <dl class="clearfix" style="width: ' + ( ( histogram_values[key] / histogram_max ) * 100 ) + '%;">' + "\n" +
' <dt><span>' + app.format_number( key ) + '</span></dt>' + "\n" +
' <dd><span>' + app.format_number( histogram_values[key] ) + '</span></dd>' + "\n" +
' </dl>' + "\n" +
'</li>'
);
}
$( 'dl', histogram_holder_element )
.html( histogram_legend );
$( 'ul', histogram_holder_element )
.html( histogram_entries.join( "\n" ) );
var histogram_values = luke_array_to_struct( field_data.histogram ).values;
$( 'ul li:even', histogram_holder_element )
.addClass( 'odd' );
histogram_element
.sparkline
(
histogram_values,
{
type : 'bar',
barColor : '#c0c0c0',
zeroColor : '#000000',
height : histogram_element.height(),
barWidth : 46,
barSpacing : 3
}
);
1 === histogram_values.length
? histogram_element.addClass( 'single' )
: histogram_element.removeClass( 'single' );
var max_width = 10 + Math.max.apply( Math, $( 'dt', histogram_holder_element ).map( get_width ).get() );
additional_styles.push
(
histogram_holder_element.selector + ' ul { margin-left: ' + max_width + 'px !important; }' + "\n" +
histogram_holder_element.selector + ' li dt { left: ' + ( max_width * -1 ) + 'px !important; width: ' + max_width + 'px !important; }'
);
}
if( additional_styles )
{
terminfo_element
.prepend( '<style type="text/css">' + additional_styles.join( "\n" ) + '</style>' );
}
},
error : function( xhr, text_status, error_thrown)
{
terminfo_element
.addClass( 'disabled' );
},
complete : function( xhr, text_status )
{
$( 'span', trigger_element )
.removeClass( 'loader' );
}
}
);

View File

@ -158,12 +158,8 @@ limitations under the License.
<p class="head">Histogram:</p>
<div class="histogram"></div>
<ul></ul>
<dl class="clearfix">
</dl>
</div>
</div>