blob: 8eaac46938503a1e7bd689eeda1641487b044341 [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.simpletext;
import java.io.IOException;
import org.apache.lucene.codecs.CompetitiveImpactAccumulator;
import org.apache.lucene.codecs.FieldsConsumer;
import org.apache.lucene.codecs.NormsProducer;
import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.FieldInfos;
import org.apache.lucene.index.Fields;
import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.PostingsEnum;
import org.apache.lucene.index.SegmentWriteState;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder;
class SimpleTextFieldsWriter extends FieldsConsumer {
private IndexOutput out;
private final BytesRefBuilder scratch = new BytesRefBuilder();
private final SegmentWriteState writeState;
final String segment;
/** for write skip data. */
private int docCount = 0;
private final SimpleTextSkipWriter skipWriter;
private final CompetitiveImpactAccumulator competitiveImpactAccumulator =
new CompetitiveImpactAccumulator();
private long lastDocFilePointer = -1;
static final BytesRef END = new BytesRef("END");
static final BytesRef FIELD = new BytesRef("field ");
static final BytesRef TERM = new BytesRef(" term ");
static final BytesRef DOC = new BytesRef(" doc ");
static final BytesRef FREQ = new BytesRef(" freq ");
static final BytesRef POS = new BytesRef(" pos ");
static final BytesRef START_OFFSET = new BytesRef(" startOffset ");
static final BytesRef END_OFFSET = new BytesRef(" endOffset ");
static final BytesRef PAYLOAD = new BytesRef(" payload ");
public SimpleTextFieldsWriter(SegmentWriteState writeState) throws IOException {
final String fileName = SimpleTextPostingsFormat.getPostingsFileName(writeState.segmentInfo.name, writeState.segmentSuffix);
segment = writeState.segmentInfo.name;
out = writeState.directory.createOutput(fileName, writeState.context);
this.writeState = writeState;
this.skipWriter = new SimpleTextSkipWriter(writeState);
}
@Override
public void write(Fields fields, NormsProducer norms) throws IOException {
write(writeState.fieldInfos, fields, norms);
}
public void write(FieldInfos fieldInfos, Fields fields, NormsProducer normsProducer)
throws IOException {
// for each field
for(String field : fields) {
Terms terms = fields.terms(field);
if (terms == null) {
// Annoyingly, this can happen!
continue;
}
FieldInfo fieldInfo = fieldInfos.fieldInfo(field);
boolean wroteField = false;
boolean hasPositions = terms.hasPositions();
boolean hasFreqs = terms.hasFreqs();
boolean hasPayloads = fieldInfo.hasPayloads();
boolean hasOffsets = terms.hasOffsets();
boolean fieldHasNorms = fieldInfo.hasNorms();
NumericDocValues norms = null;
if (fieldHasNorms && normsProducer != null) {
norms = normsProducer.getNorms(fieldInfo);
}
int flags = 0;
if (hasPositions) {
flags = PostingsEnum.POSITIONS;
if (hasPayloads) {
flags = flags | PostingsEnum.PAYLOADS;
}
if (hasOffsets) {
flags = flags | PostingsEnum.OFFSETS;
}
} else {
if (hasFreqs) {
flags = flags | PostingsEnum.FREQS;
}
}
TermsEnum termsEnum = terms.iterator();
PostingsEnum postingsEnum = null;
// for each term in field
while(true) {
BytesRef term = termsEnum.next();
if (term == null) {
break;
}
docCount = 0;
skipWriter.resetSkip();
competitiveImpactAccumulator.clear();
lastDocFilePointer = -1;
postingsEnum = termsEnum.postings(postingsEnum, flags);
assert postingsEnum != null: "termsEnum=" + termsEnum + " hasPos=" + hasPositions + " flags=" + flags;
boolean wroteTerm = false;
// for each doc in field+term
while(true) {
int doc = postingsEnum.nextDoc();
if (doc == PostingsEnum.NO_MORE_DOCS) {
break;
}
if (!wroteTerm) {
if (!wroteField) {
// we lazily do this, in case the field had
// no terms
write(FIELD);
write(field);
newline();
wroteField = true;
}
// we lazily do this, in case the term had
// zero docs
write(TERM);
write(term);
newline();
wroteTerm = true;
}
if (lastDocFilePointer == -1) {
lastDocFilePointer = out.getFilePointer();
}
write(DOC);
write(Integer.toString(doc));
newline();
if (hasFreqs) {
int freq = postingsEnum.freq();
write(FREQ);
write(Integer.toString(freq));
newline();
if (hasPositions) {
// for assert:
int lastStartOffset = 0;
// for each pos in field+term+doc
for(int i=0;i<freq;i++) {
int position = postingsEnum.nextPosition();
write(POS);
write(Integer.toString(position));
newline();
if (hasOffsets) {
int startOffset = postingsEnum.startOffset();
int endOffset = postingsEnum.endOffset();
assert endOffset >= startOffset;
assert startOffset >= lastStartOffset: "startOffset=" + startOffset + " lastStartOffset=" + lastStartOffset;
lastStartOffset = startOffset;
write(START_OFFSET);
write(Integer.toString(startOffset));
newline();
write(END_OFFSET);
write(Integer.toString(endOffset));
newline();
}
BytesRef payload = postingsEnum.getPayload();
if (payload != null && payload.length > 0) {
assert payload.length != 0;
write(PAYLOAD);
write(payload);
newline();
}
}
}
competitiveImpactAccumulator.add(freq, getNorm(doc, norms));
} else {
competitiveImpactAccumulator.add(1, getNorm(doc, norms));
}
docCount++;
if (docCount != 0 && docCount % SimpleTextSkipWriter.BLOCK_SIZE == 0) {
skipWriter.bufferSkip(doc, lastDocFilePointer, docCount, competitiveImpactAccumulator);
competitiveImpactAccumulator.clear();
lastDocFilePointer = -1;
}
}
if (docCount >= SimpleTextSkipWriter.BLOCK_SIZE) {
skipWriter.writeSkip(out);
}
}
}
}
private void write(String s) throws IOException {
SimpleTextUtil.write(out, s, scratch);
}
private void write(BytesRef b) throws IOException {
SimpleTextUtil.write(out, b);
}
private void newline() throws IOException {
SimpleTextUtil.writeNewline(out);
}
@Override
public void close() throws IOException {
if (out != null) {
try {
write(END);
newline();
SimpleTextUtil.writeChecksum(out, scratch);
} finally {
out.close();
out = null;
}
}
}
private long getNorm(int doc, NumericDocValues norms) throws IOException {
if (norms == null) {
return 1L;
}
boolean found = norms.advanceExact(doc);
if (found == false) {
return 1L;
}
return norms.longValue();
}
}