blob: c21fc016bc92b01d80307d1cb9ffd681271b354e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.codecs;
import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.index.DocIDMerger;
import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.MergeState;
import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.SegmentWriteState;
/**
* Abstract API that consumes normalization values.
* Concrete implementations of this
* actually do "something" with the norms (write it into
* the index in a specific format).
* <p>
* The lifecycle is:
* <ol>
* <li>NormsConsumer is created by
* {@link NormsFormat#normsConsumer(SegmentWriteState)}.
* <li>{@link #addNormsField} is called for each field with
* normalization values. The API is a "pull" rather
* than "push", and the implementation is free to iterate over the
* values multiple times ({@link Iterable#iterator()}).
* <li>After all fields are added, the consumer is {@link #close}d.
* </ol>
*
* @lucene.experimental
*/
public abstract class NormsConsumer implements Closeable {
/** Sole constructor. (For invocation by subclass
* constructors, typically implicit.) */
protected NormsConsumer() {}
/**
* Writes normalization values for a field.
* @param field field information
* @param normsProducer NormsProducer of the numeric norm values
* @throws IOException if an I/O error occurred.
*/
public abstract void addNormsField(FieldInfo field, NormsProducer normsProducer) throws IOException;
/** Merges in the fields from the readers in
* <code>mergeState</code>. The default implementation
* calls {@link #mergeNormsField} for each field,
* filling segments with missing norms for the field with zeros.
* Implementations can override this method
* for more sophisticated merging (bulk-byte copying, etc). */
public void merge(MergeState mergeState) throws IOException {
for(NormsProducer normsProducer : mergeState.normsProducers) {
if (normsProducer != null) {
normsProducer.checkIntegrity();
}
}
for (FieldInfo mergeFieldInfo : mergeState.mergeFieldInfos) {
if (mergeFieldInfo.hasNorms()) {
mergeNormsField(mergeFieldInfo, mergeState);
}
}
}
/** Tracks state of one numeric sub-reader that we are merging */
private static class NumericDocValuesSub extends DocIDMerger.Sub {
private final NumericDocValues values;
public NumericDocValuesSub(MergeState.DocMap docMap, NumericDocValues values) {
super(docMap);
this.values = values;
assert values.docID() == -1;
}
@Override
public int nextDoc() throws IOException {
return values.nextDoc();
}
}
/**
* Merges the norms from <code>toMerge</code>.
* <p>
* The default implementation calls {@link #addNormsField}, passing
* an Iterable that merges and filters deleted documents on the fly.
*/
public void mergeNormsField(final FieldInfo mergeFieldInfo, final MergeState mergeState) throws IOException {
// TODO: try to share code with default merge of DVConsumer by passing MatchAllBits ?
addNormsField(mergeFieldInfo,
new NormsProducer() {
@Override
public NumericDocValues getNorms(FieldInfo fieldInfo) throws IOException {
if (fieldInfo != mergeFieldInfo) {
throw new IllegalArgumentException("wrong fieldInfo");
}
List<NumericDocValuesSub> subs = new ArrayList<>();
assert mergeState.docMaps.length == mergeState.docValuesProducers.length;
for (int i=0;i<mergeState.docValuesProducers.length;i++) {
NumericDocValues norms = null;
NormsProducer normsProducer = mergeState.normsProducers[i];
if (normsProducer != null) {
FieldInfo readerFieldInfo = mergeState.fieldInfos[i].fieldInfo(mergeFieldInfo.name);
if (readerFieldInfo != null && readerFieldInfo.hasNorms()) {
norms = normsProducer.getNorms(readerFieldInfo);
}
}
if (norms != null) {
subs.add(new NumericDocValuesSub(mergeState.docMaps[i], norms));
}
}
final DocIDMerger<NumericDocValuesSub> docIDMerger = DocIDMerger.of(subs, mergeState.needsIndexSort);
return new NumericDocValues() {
private int docID = -1;
private NumericDocValuesSub current;
@Override
public int docID() {
return docID;
}
@Override
public int nextDoc() throws IOException {
current = docIDMerger.next();
if (current == null) {
docID = NO_MORE_DOCS;
} else {
docID = current.mappedDocID;
}
return docID;
}
@Override
public int advance(int target) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public boolean advanceExact(int target) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public long cost() {
return 0;
}
@Override
public long longValue() throws IOException {
return current.values.longValue();
}
};
}
@Override
public void checkIntegrity() {
}
@Override
public void close() {
}
@Override
public long ramBytesUsed() {
return 0;
}
});
}
}