jackrabbit in action seven(インデックスマージ(上))
15058 ワード
私たちはテキスト抽出の論理から出て、主体プロセスに戻ります.
前の記事では、インデックス作成の操作を1回見ることができます.複数のpersistentindexオブジェクトが生成される可能性がありますが、これらのオブジェクトはインデックスディレクトリを表しています.インデックスの作成回数が増えるにつれて、インデックスディレクトリも増えていますが、インデックスディレクトリのデータは多くありません.そのため、複数のディレクトリをマージする必要があります.つまり、インデックスのマージです.
この操作を実行するクラスはIndexMergerで、次のように定義されています.
IndexMergerの作成が完了すると、PersistentIndexを追加する可能性があります.MergerクラスはどのPersistentIndexがMergerを必要としているかを知る必要があります.では、この論理を担当するコードを見てみましょう.このコードは主に3つの機能を担当し、1つはindexBucketsを初期化し、このArrayListを初期化します.その中にはMergerのPersistentIndexが必要なリスト、つまりindexBucketに入っているのかlistなのかを考えることができますが、ここには非常に奇妙な設計があります.初期化時にPersistentIndexをdocnumsの範囲でグループ化し、一組がindexBucketです.
2つ目は、追加する必要があるPersistentIndexを対応するパケットに追加することです.
3つ目は、マージが必要かどうかを判断し、必要に応じてキューに追加し、マージを待つことです.
まず、最初のコードを見てください.
すなわちnew IndexBucket(0 100,rue)
2つ目はnew IndexBucket(101,100*10,t rue)
3つ目はnew IndexBucket(1001,100*10*10,t rue)
4つ目はnew IndexBucket(10001,100*10*10,t rue)
5つ目はnew IndexBucket(100001,100*10*10,t rue)
````````````
upperが2147483647未満で、10の最大べき乗になるまで続けます.つまり10億、1つのディレクトリに10億個のdocumentのindexデータがある場合、このディレクトリはmergeプロセスに参加しません.indexBucketsには全部で8個のIndexBucketがありますが、ループの外にはIndexBucketを作成する文が2つありますが、この2つは合併に参加することは許されません.そのため、3番目のパラメータはfalseです.つまり全部で10個、9つ目は:
前の記事では、インデックス作成の操作を1回見ることができます.複数のpersistentindexオブジェクトが生成される可能性がありますが、これらのオブジェクトはインデックスディレクトリを表しています.インデックスの作成回数が増えるにつれて、インデックスディレクトリも増えていますが、インデックスディレクトリのデータは多くありません.そのため、複数のディレクトリをマージする必要があります.つまり、インデックスのマージです.
この操作を実行するクラスはIndexMergerで、次のように定義されています.
class IndexMerger extends Thread implements IndexListener
/* , listener , :
*/
IndexMerger(MultiIndex multiIndex) {
this.multiIndex = multiIndex;
setName("IndexMerger");
setDaemon(true);
try {
mergerIdle.acquire();
} catch (InterruptedException e) {
// will never happen, lock is free upon construction
throw new InternalError("Unable to acquire mutex after construction");
}
}
まだdeamonスレッドです.そして構造するとmergerIdle.acquire()が来ました.待ちきれないですね.どういう意味ですか?ロックが1つ、ブロックされていないロックが1つ得られます.IndexMergerの作成が完了すると、PersistentIndexを追加する可能性があります.MergerクラスはどのPersistentIndexがMergerを必要としているかを知る必要があります.では、この論理を担当するコードを見てみましょう.このコードは主に3つの機能を担当し、1つはindexBucketsを初期化し、このArrayListを初期化します.その中にはMergerのPersistentIndexが必要なリスト、つまりindexBucketに入っているのかlistなのかを考えることができますが、ここには非常に奇妙な設計があります.初期化時にPersistentIndexをdocnumsの範囲でグループ化し、一組がindexBucketです.
2つ目は、追加する必要があるPersistentIndexを対応するパケットに追加することです.
3つ目は、マージが必要かどうかを判断し、必要に応じてキューに追加し、マージを待つことです.
まず、最初のコードを見てください.
synchronized (lock) {
// initially create buckets
if (indexBuckets.size() == 0) {
long lower = 0;
// default minMergeDocs is 100
long upper = minMergeDocs;
//default maxMergeDocs is 2147483647
// IndexBucket ArrayList
while (upper < maxMergeDocs) {
indexBuckets.add(new IndexBucket(lower, upper, true));
lower = upper + 1;
//default mergeFactor is 10
upper *= mergeFactor;
}
// one with upper = maxMergeDocs
indexBuckets.add(new IndexBucket(lower, maxMergeDocs, false));
// and another one as overflow, just in case...
indexBuckets.add(new IndexBucket(maxMergeDocs + 1, Long.MAX_VALUE, false));
}
············
コードをよく読むと、indexBucketsを初期化するコードでは、最初のIndexBucketを追加したときにlower=0、upper=100などの範囲で初期化されていることがわかります.すなわちnew IndexBucket(0 100,rue)
2つ目はnew IndexBucket(101,100*10,t rue)
3つ目はnew IndexBucket(1001,100*10*10,t rue)
4つ目はnew IndexBucket(10001,100*10*10,t rue)
5つ目はnew IndexBucket(100001,100*10*10,t rue)
````````````
upperが2147483647未満で、10の最大べき乗になるまで続けます.つまり10億、1つのディレクトリに10億個のdocumentのindexデータがある場合、このディレクトリはmergeプロセスに参加しません.indexBucketsには全部で8個のIndexBucketがありますが、ループの外にはIndexBucketを作成する文が2つありますが、この2つは合併に参加することは許されません.そのため、3番目のパラメータはfalseです.つまり全部で10個、9つ目は:
new IndexBucket(1000000001, 2147483647, false)
:
new IndexBucket(2147483648, 0x7fffffffffffffffL, false)
indexBuckets , , docNums persistentindex IndexBucket :
// put index in bucket
IndexBucket bucket = (IndexBucket) indexBuckets.get(indexBuckets.size() - 1);
for (int i = 0; i < indexBuckets.size(); i++) {
bucket = (IndexBucket) indexBuckets.get(i);
if (bucket.fits(numDocs)) {
break;
}
}
/* indexBuckets , Index 10 IndexBucket , indexBuckets IndexBucket , numDocs IndexBucket 。*/
bucket.add(new Index(name, numDocs));
if (log.isDebugEnabled()) {
log.debug("index added: name=" + name + ", numDocs=" + numDocs);
}
// if bucket does not allow merge, we don't have to continue
// IndexBucket,
if (!bucket.allowsMerge()) {
return;
}
/* , 3 :
*/ // check if we need a merge
// indexbucket 10 < 10 >
if (bucket.size() >= mergeFactor) {
long targetMergeDocs = bucket.upper;
targetMergeDocs = Math.min(targetMergeDocs * mergeFactor, maxMergeDocs);
// sum up docs in bucket
List indexesToMerge = new ArrayList();
int mergeDocs = 0;
for (Iterator it = bucket.iterator(); it.hasNext() && mergeDocs <= targetMergeDocs;) {
indexesToMerge.add(it.next());
}
/* ,indexesToMerge.size() 2 ?????*/
if (indexesToMerge.size() > 2) {
// found merge
Index[] idxs = (Index[]) indexesToMerge.toArray(new Index[indexesToMerge.size()]);
bucket.removeAll(indexesToMerge);
if (log.isDebugEnabled()) {
log.debug("requesting merge for " + indexesToMerge);
}
mergeTasks.add(new Merge(idxs));
log.debug("merge queue now contains " + mergeTasks.size() + " tasks.");
}
}
このコードの な はindexbucketのpersistentindex を り し、 が2を えるとキューに し、indexbucketから することです.この では、mergeTasksキューにマージするindexがいくつか します.
ミッドフィールドのまとめ:
の と のインデックスによって された では、ramdirectoryの100を えるdocsのindex dataをfsdirectoryにブラシすると、 しいfsdirectoryのディレクトリとして しいディレクトリを し、このfsdirectoryに するPersistentIndexをIndexMergerクラスのあるIndexBucketに します. に、あるIndexBucketのPersistentIndexの (すなわち、これらのディレクトリの )が10(mergefactor)を えると
)を すると、マージ が されます.
では、 の は、 、この10つのディレクトリはどこへ くのか、 の9つをそのうちの1つに するのか、それともどのように するのかということです. けてみましょう.
らかに、ここではまた モデルを し、indexAddedメソッドを び すすべての 、 はいくつかの に づいて、 する があるpersistentindexをmergeTasksのキューに し、 が がいるに いない. の で べたように、IndexMergerクラスはdeamonスレッドであり、runメソッドを てみましょう.では、 には であることがわかります. に の を します.
1 が いているかどうかを する
2キューに コマンドがあるかどうかを する
3 きがあればwait に る
4 persistentindexの に ってすべてのpersistentindexを ります
のIndexReaderオブジェクト
5 しいPersistentIndexを し、 のindexファイルをこの しいディレクトリにマージします.
6 のIndexReaderオブジェクトをPersistentIndexのindexwriterメソッドに し、optimizeを します.
7これらのreadersを じる
8マージされたPersistentIndexのインデックスファイルやディレクトリなどを によって します.
コードを てみましょう.ahuaxuanのコメントが されています.public void run() {
for (;;) {
boolean isIdle = false;
// 0, , wait
if (mergeTasks.size() == 0) {
mergerIdle.release();
isIdle = true;
}
/*2
*/
Merge task = (Merge) mergeTasks.remove();
if (task == QUIT) {
mergerIdle.release();
break;
}
if (isIdle) {
try {
mergerIdle.acquire();
} catch (InterruptedException e) {
Thread.interrupted();
log.warn("Unable to acquire mergerIdle sync");
}
}
log.debug("accepted merge request");
// reset deleted documents
deletedDocuments.clear();
// get readers
/*4 persistentindex persistentindex
IndexReader
*/
String[] names = new String[task.indexes.length];
for (int i = 0; i < task.indexes.length; i++) {
names[i] = task.indexes[i].name;
}
try {
log.debug("create new index");
/* PersistentIndex, index
*/
PersistentIndex index = multiIndex.getOrCreateIndex(null);
boolean success = false;
try {
log.debug("get index readers from MultiIndex");
IndexReader[] readers = multiIndex.getIndexReaders(names, this);
try {
// do the merge
long time = System.currentTimeMillis();
/*6 IndexReader PersistentIndex indexwriter , optimize。
*/
index.addIndexes(readers);
time = System.currentTimeMillis() - time;
int docCount = 0;
for (int i = 0; i < readers.length; i++) {
docCount += readers[i].numDocs();
}
log.info("merged " + docCount + " documents in " + time + " ms into " + index.getName() + ".");
} finally {
for (int i = 0; i < readers.length; i++) {
/*7 readers
*/
try {
readers[i].close();
} catch (IOException e) {
log.warn("Unable to close IndexReader: " + e);
}
}
}
// inform multi index
// if we cannot get the sync immediately we have to quit
if (!indexReplacement.attempt(0)) {
log.debug("index merging canceled");
break;
}
try {
log.debug("replace indexes");
multiIndex.replaceIndexes(names, index, deletedDocuments);
} finally {
indexReplacement.release();
}
success = true;
} finally {
if (!success) {
// delete index
log.debug("deleting index " + index.getName());
/*8 PersistentIndex 。
*/
multiIndex.deleteIndex(index);
}
}
} catch (Throwable e) {
log.error("Error while merging indexes: " + e);
}
}
log.info("IndexMerger terminated");
}
ここでよく えている たちは、ここに が れているのか、 なのかを しているに いない. したように、1つのbucketに10 のディレクトリがあると、 しいディレクトリがマージされます.つまり、この しいディレクトリには なくとも1000 のdocumentのインデックスデータがあります.このようにして、もし が100000 のノードを っていて、ちょうど ディレクトリの1000 のdocumentのデータがあれば、100 のディレクトリでデータを しなければなりません.このような は、クエリを うたびに100 のindexReaderをsearchに す があり、マルチスレッド を してもディレクトリ が すぎて、しかも
100 w のノードは、さらに なのでjackrabbitには、これらのディレクトリをより きなディレクトリに するメカニズムがあるに いありません.なぜかというと、 はindexbucketを するときに、 を するセグメントが8つに かれていたので、 の は のbucketしか われておらず、 ろのいくつかは に つに いありません.では、 がトリガーしたのでしょうか.どこにあるのでしょうか.
のrunメソッドでは、multiIndex.replaceIndexes(names,index,deleteddDocuments)という があります.
たちはこの の で を して、 にahuaxuanはコードの で の を えました/* obsoleteIndexes dir , , index PersistentIndex , deleted */
void replaceIndexes(String[] obsoleteIndexes,
PersistentIndex index,
Collection deleted)
throws IOException {
/* multiIndex , synchronized , multiindex , ? */
synchronized (this) {
/* multiIndex#update , , */
synchronized (updateMonitor) {
updateInProgress = true;
}
try {
// if we are reindexing there is already an active transaction
if (!reindexing) {
executeAndLog(new Start(Action.INTERNAL_TRANS_REPL_INDEXES));
}
// delete obsolete indexes
/*10 , 10 , */
Set names = new HashSet(Arrays.asList(obsoleteIndexes));
for (Iterator it = names.iterator(); it.hasNext();) {
// do not try to delete indexes that are already gone
String indexName = (String) it.next();
if (indexNames.contains(indexName)) {
executeAndLog(new DeleteIndex(getTransactionId(), indexName));
}
}
// Index merger does not log an action when it creates the target
// index of the merge. We have to do this here.
/* CreateIndex ? : PersistentIndex , null, PersistentIndex , , PersistentIndex */
executeAndLog(new CreateIndex(getTransactionId(), index.getName()));
/* AddIndex , , persistentIndex */
executeAndLog(new AddIndex(getTransactionId(), index.getName()));
// delete documents in index
for (Iterator it = deleted.iterator(); it.hasNext();) {
Term id = (Term) it.next();
index.removeDocument(id);
}
index.commit();
if (!reindexing) {
// only commit if we are not reindexing
// when reindexing the final commit is done at the very end
executeAndLog(new Commit(getTransactionId()));
}
} finally {
synchronized (updateMonitor) {
updateInProgress = false;
updateMonitor.notifyAll();
releaseMultiReader();
}
}
}
if (reindexing) {
// do some cleanup right away when reindexing
attemptDelete();
}
}
この を てみると、 さなディレクトリが きなディレクトリにマージされた 、この きなディレクトリはindexbucketに されて のマージを つことに づきました.このように に、1つのディレクトリのdocumentのindexデータが10 を えると、もうマージされません.ahuaxuanは を きました.
=========================================================================
の0-100は のディレクトリレベルを し、これらのディレクトリには0-100 のdocumentのindexデータしか まれていないが、デフォルトのパラメータの 、これらのディレクトリはまったく ない. のプロセスでは、ramdirectoryのデータがfsdirectoryに するのは100 であることが らかになった.これは、 に したディレクトリが101-1000レベルのディレクトリであることを する.(101-1000のディレクトリは、これらのディレクトリのdocumentのindexデータも101-1000 の しかありません.).このディレクトリが10 を えると しいディレクトリにマージされます. ディレクトリを に します. のahuaxuanのコメントを してください.
ここまで うと、 くのパラメータがマージのチューニングを できることはよく られていますが、これらのパラメータは したように、これ しません.
ここまで、IndexMergerの プロセスは に していますが、 は1つの - モデル+ ディレクトリ ディレクトリであり、 ディレクトリがより ディレクトリを するアルゴリズムのメリットは ですか?もちろんインデックスファイルをできるだけ なく することであり、 のクエリーアーキテクチャと えるはずです.しかし、 するjackrabbitはまだ していないことを しく します のクエリーの ができている は、そのこの はまだ されなければならない. は ではない.フレームワークもそうである.あまり しく めなくても、 を う もない.
TO BE CONTINUE