--- /dev/null
+package org.apache.lucene.index;
+
+import org.apache.lucene.util.StringHelper;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+/*
+ * Licensed 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.
+ *
+ */
+
+
+/**
+ * Transparent access to the vector space model,
+ * either via TermFreqVector or by resolving it from the inverted index.
+ * <p/>
+ * Resolving a term vector from a large index can be a time consuming process.
+ * <p/>
+ * Warning! This class is not thread safe!
+ */
+public class TermVectorAccessor {
+
+ public TermVectorAccessor() {
+ }
+
+ /**
+ * Instance reused to save garbage collector some time
+ */
+ private TermVectorMapperDecorator decoratedMapper = new TermVectorMapperDecorator();
+
+
+ /**
+ * Visits the TermVectorMapper and populates it with terms available for a given document,
+ * either via a vector created at index time or by resolving them from the inverted index.
+ *
+ * @param indexReader Index source
+ * @param documentNumber Source document to access
+ * @param fieldName Field to resolve
+ * @param mapper Mapper to be mapped with data
+ * @throws IOException
+ */
+ public void accept(IndexReader indexReader, int documentNumber, String fieldName, TermVectorMapper mapper) throws IOException {
+
+ fieldName = StringHelper.intern(fieldName);
+
+ decoratedMapper.decorated = mapper;
+ decoratedMapper.termVectorStored = false;
+
+ indexReader.getTermFreqVector(documentNumber, fieldName, decoratedMapper);
+
+ if (!decoratedMapper.termVectorStored) {
+ mapper.setDocumentNumber(documentNumber);
+ build(indexReader, fieldName, mapper, documentNumber);
+ }
+ }
+
+ /** Instance reused to save garbage collector some time */
+ private List<String> tokens;
+
+ /** Instance reused to save garbage collector some time */
+ private List<int[]> positions;
+
+ /** Instance reused to save garbage collector some time */
+ private List<Integer> frequencies;
+
+
+ /**
+ * Populates the mapper with terms available for the given field in a document
+ * by resolving the inverted index.
+ *
+ * @param indexReader
+ * @param field interned field name
+ * @param mapper
+ * @param documentNumber
+ * @throws IOException
+ */
+ private void build(IndexReader indexReader, String field, TermVectorMapper mapper, int documentNumber) throws IOException {
+
+ if (tokens == null) {
+ tokens = new ArrayList<String>(500);
+ positions = new ArrayList<int[]>(500);
+ frequencies = new ArrayList<Integer>(500);
+ } else {
+ tokens.clear();
+ frequencies.clear();
+ positions.clear();
+ }
+
+ TermEnum termEnum = indexReader.terms(new Term(field, ""));
+ if (termEnum.term() != null) {
+ while (termEnum.term().field() == field) {
+ TermPositions termPositions = indexReader.termPositions(termEnum.term());
+ if (termPositions.skipTo(documentNumber)) {
+
+ frequencies.add(Integer.valueOf(termPositions.freq()));
+ tokens.add(termEnum.term().text());
+
+
+ if (!mapper.isIgnoringPositions()) {
+ int[] positions = new int[termPositions.freq()];
+ for (int i = 0; i < positions.length; i++) {
+ positions[i] = termPositions.nextPosition();
+ }
+ this.positions.add(positions);
+ } else {
+ positions.add(null);
+ }
+ }
+ termPositions.close();
+ if (!termEnum.next()) {
+ break;
+ }
+ }
+ mapper.setDocumentNumber(documentNumber);
+ mapper.setExpectations(field, tokens.size(), false, !mapper.isIgnoringPositions());
+ for (int i = 0; i < tokens.size(); i++) {
+ mapper.map(tokens.get(i), frequencies.get(i).intValue(), (TermVectorOffsetInfo[]) null, positions.get(i));
+ }
+ }
+ termEnum.close();
+
+
+ }
+
+
+ private static class TermVectorMapperDecorator extends TermVectorMapper {
+
+ private TermVectorMapper decorated;
+
+ @Override
+ public boolean isIgnoringPositions() {
+ return decorated.isIgnoringPositions();
+ }
+
+ @Override
+ public boolean isIgnoringOffsets() {
+ return decorated.isIgnoringOffsets();
+ }
+
+ private boolean termVectorStored = false;
+
+ @Override
+ public void setExpectations(String field, int numTerms, boolean storeOffsets, boolean storePositions) {
+ decorated.setExpectations(field, numTerms, storeOffsets, storePositions);
+ termVectorStored = true;
+ }
+
+ @Override
+ public void map(String term, int frequency, TermVectorOffsetInfo[] offsets, int[] positions) {
+ decorated.map(term, frequency, offsets, positions);
+ }
+
+ @Override
+ public void setDocumentNumber(int documentNumber) {
+ decorated.setDocumentNumber(documentNumber);
+ }
+ }
+
+}