1
package org.apache.lucene.index;
4
* Licensed to the Apache Software Foundation (ASF) under one or more
5
* contributor license agreements. See the NOTICE file distributed with
6
* this work for additional information regarding copyright ownership.
7
* The ASF licenses this file to You under the Apache License, Version 2.0
8
* (the "License"); you may not use this file except in compliance with
9
* the License. You may obtain a copy of the License at
11
* http://www.apache.org/licenses/LICENSE-2.0
13
* Unless required by applicable law or agreed to in writing, software
14
* distributed under the License is distributed on an "AS IS" BASIS,
15
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
* See the License for the specific language governing permissions and
17
* limitations under the License.
20
import java.io.Closeable;
21
import java.io.IOException;
22
import java.util.Collection;
23
import java.util.Collections;
24
import java.util.Random;
26
import org.apache.lucene.analysis.Analyzer;
27
import org.apache.lucene.analysis.MockAnalyzer;
28
import org.apache.lucene.document.Document;
29
import org.apache.lucene.index.IndexWriter; // javadoc
30
import org.apache.lucene.search.Query;
31
import org.apache.lucene.store.Directory;
32
import org.apache.lucene.util.LuceneTestCase;
33
import org.apache.lucene.util.Version;
34
import org.apache.lucene.util._TestUtil;
36
/** Silly class that randomizes the indexing experience. EG
37
* it may swap in a different merge policy/scheduler; may
38
* commit periodically; may or may not optimize in the end,
39
* may flush by doc count instead of RAM, etc.
42
public class RandomIndexWriter implements Closeable {
45
private final Random r;
48
private double flushAtFactor = 1.0;
49
private boolean getReaderCalled;
51
// Randomly calls Thread.yield so we mixup thread scheduling
52
private static final class MockIndexWriter extends IndexWriter {
54
private final Random r;
56
public MockIndexWriter(Random r,Directory dir, IndexWriterConfig conf) throws IOException {
58
// must make a private random since our methods are
59
// called from different threads; else test failures may
60
// not be reproducible from the original seed
61
this.r = new Random(r.nextInt());
65
boolean testPoint(String name) {
66
if (r.nextInt(4) == 2)
72
/** create a RandomIndexWriter with a random config: Uses TEST_VERSION_CURRENT and Whitespace+LowercasingAnalyzer */
73
public RandomIndexWriter(Random r, Directory dir) throws IOException {
74
this(r, dir, LuceneTestCase.newIndexWriterConfig(r, LuceneTestCase.TEST_VERSION_CURRENT, new MockAnalyzer(r)));
77
/** create a RandomIndexWriter with a random config: Uses TEST_VERSION_CURRENT */
78
public RandomIndexWriter(Random r, Directory dir, Analyzer a) throws IOException {
79
this(r, dir, LuceneTestCase.newIndexWriterConfig(r, LuceneTestCase.TEST_VERSION_CURRENT, a));
82
/** create a RandomIndexWriter with a random config */
83
public RandomIndexWriter(Random r, Directory dir, Version v, Analyzer a) throws IOException {
84
this(r, dir, LuceneTestCase.newIndexWriterConfig(r, v, a));
87
/** create a RandomIndexWriter with the provided config */
88
public RandomIndexWriter(Random r, Directory dir, IndexWriterConfig c) throws IOException {
90
w = new MockIndexWriter(r, dir, c);
91
flushAt = _TestUtil.nextInt(r, 10, 1000);
92
if (LuceneTestCase.VERBOSE) {
93
System.out.println("RIW config=" + w.getConfig());
99
* @see IndexWriter#addDocument(Document)
101
public void addDocument(final Document doc) throws IOException {
102
if (r.nextInt(5) == 3) {
103
// TODO: maybe, we should simply buffer up added docs
104
// (but we need to clone them), and only when
105
// getReader, commit, etc. are called, we do an
106
// addDocuments? Would be better testing.
107
w.addDocuments(Collections.singletonList(doc));
114
public void addDocuments(Collection<Document> docs) throws IOException {
115
w.addDocuments(docs);
119
public void updateDocuments(Term delTerm, Collection<Document> docs) throws IOException {
120
w.updateDocuments(delTerm, docs);
124
private void maybeCommit() throws IOException {
125
if (docCount++ == flushAt) {
126
if (LuceneTestCase.VERBOSE) {
127
System.out.println("RIW.add/updateDocument: now doing a commit at docCount=" + docCount);
130
flushAt += _TestUtil.nextInt(r, (int) (flushAtFactor * 10), (int) (flushAtFactor * 1000));
131
if (flushAtFactor < 2e6) {
132
// gradually but exponentially increase time b/w flushes
133
flushAtFactor *= 1.05;
139
* Updates a document.
140
* @see IndexWriter#updateDocument(Term, Document)
142
public void updateDocument(Term t, final Document doc) throws IOException {
143
if (r.nextInt(5) == 3) {
144
w.updateDocuments(t, Collections.singletonList(doc));
146
w.updateDocument(t, doc);
151
public void addIndexes(Directory... dirs) throws CorruptIndexException, IOException {
155
public void deleteDocuments(Term term) throws CorruptIndexException, IOException {
156
w.deleteDocuments(term);
159
public void deleteDocuments(Query q) throws CorruptIndexException, IOException {
160
w.deleteDocuments(q);
163
public void commit() throws CorruptIndexException, IOException {
167
public int numDocs() throws IOException {
171
public int maxDoc() {
175
public void deleteAll() throws IOException {
179
private boolean doRandomOptimize = true;
180
private boolean doRandomOptimizeAssert = true;
182
public void setDoRandomOptimize(boolean v) {
183
doRandomOptimize = v;
186
public void setDoRandomOptimizeAssert(boolean v) {
187
doRandomOptimizeAssert = v;
190
private void doRandomOptimize() throws IOException {
191
if (doRandomOptimize) {
192
final int segCount = w.getSegmentCount();
193
if (r.nextBoolean() || segCount == 0) {
198
final int limit = _TestUtil.nextInt(r, 1, segCount);
200
assert !doRandomOptimizeAssert || w.getSegmentCount() <= limit: "limit=" + limit + " actual=" + w.getSegmentCount();
205
public IndexReader getReader() throws IOException {
206
return getReader(true);
209
public IndexReader getReader(boolean applyDeletions) throws IOException {
210
getReaderCalled = true;
211
if (r.nextInt(4) == 2) {
214
if (r.nextBoolean()) {
215
if (LuceneTestCase.VERBOSE) {
216
System.out.println("RIW.getReader: use NRT reader");
218
if (r.nextInt(5) == 1) {
221
return w.getReader(applyDeletions);
223
if (LuceneTestCase.VERBOSE) {
224
System.out.println("RIW.getReader: open new reader");
227
if (r.nextBoolean()) {
228
return IndexReader.open(w.getDirectory(), new KeepOnlyLastCommitDeletionPolicy(), r.nextBoolean(), _TestUtil.nextInt(r, 1, 10));
230
return w.getReader(applyDeletions);
237
* @see IndexWriter#close()
239
public void close() throws IOException {
240
// if someone isn't using getReader() API, we want to be sure to
241
// maybeOptimize since presumably they might open a reader on the dir.
242
if (getReaderCalled == false && r.nextInt(8) == 2) {
249
* Forces an optimize.
251
* NOTE: this should be avoided in tests unless absolutely necessary,
252
* as it will result in less test coverage.
253
* @see IndexWriter#optimize()
255
public void optimize() throws IOException {