All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.lucene.index.FieldInfos Maven / Gradle / Ivy

There is a newer version: 6.4.2_1
Show newest version
/*
 * 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.index;

import static org.apache.lucene.index.FieldInfo.verifySameDocValuesSkipIndex;
import static org.apache.lucene.index.FieldInfo.verifySameDocValuesType;
import static org.apache.lucene.index.FieldInfo.verifySameIndexOptions;
import static org.apache.lucene.index.FieldInfo.verifySameOmitNorms;
import static org.apache.lucene.index.FieldInfo.verifySamePointsOptions;
import static org.apache.lucene.index.FieldInfo.verifySameStoreTermVectors;
import static org.apache.lucene.index.FieldInfo.verifySameVectorOptions;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.apache.lucene.internal.hppc.IntObjectHashMap;
import org.apache.lucene.util.CollectionUtil;

/**
 * Collection of {@link FieldInfo}s (accessible by number or by name).
 *
 * @lucene.experimental
 */
public class FieldInfos implements Iterable {

  /** An instance without any fields. */
  public static final FieldInfos EMPTY = new FieldInfos(new FieldInfo[0]);

  private final boolean hasFreq;
  private final boolean hasPostings;
  private final boolean hasProx;
  private final boolean hasPayloads;
  private final boolean hasOffsets;
  private final boolean hasTermVectors;
  private final boolean hasNorms;
  private final boolean hasDocValues;
  private final boolean hasPointValues;
  private final boolean hasVectorValues;
  private final String softDeletesField;

  private final String parentField;

  // used only by fieldInfo(int)
  private final FieldInfo[] byNumber;
  private final HashMap byName;

  /** Iterator in ascending order of field number. */
  private final Collection values;

  /**
   * Constructs a new FieldInfos from an array of FieldInfo objects. The array can be used directly
   * as the backing structure.
   */
  public FieldInfos(FieldInfo[] infos) {
    boolean hasTermVectors = false;
    boolean hasPostings = false;
    boolean hasProx = false;
    boolean hasPayloads = false;
    boolean hasOffsets = false;
    boolean hasFreq = false;
    boolean hasNorms = false;
    boolean hasDocValues = false;
    boolean hasPointValues = false;
    boolean hasVectorValues = false;
    String softDeletesField = null;
    String parentField = null;

    byName = CollectionUtil.newHashMap(infos.length);
    int maxFieldNumber = -1;
    boolean fieldNumberStrictlyAscending = true;
    for (FieldInfo info : infos) {
      int fieldNumber = info.number;
      if (fieldNumber < 0) {
        throw new IllegalArgumentException(
            "illegal field number: " + info.number + " for field " + info.name);
      }
      if (maxFieldNumber < fieldNumber) {
        maxFieldNumber = fieldNumber;
      } else {
        fieldNumberStrictlyAscending = false;
      }
      FieldInfo previous = byName.put(info.name, info);
      if (previous != null) {
        throw new IllegalArgumentException(
            "duplicate field names: "
                + previous.number
                + " and "
                + info.number
                + " have: "
                + info.name);
      }

      hasTermVectors |= info.hasTermVectors();
      hasPostings |= info.getIndexOptions() != IndexOptions.NONE;
      hasProx |= info.getIndexOptions().compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) >= 0;
      hasFreq |= info.getIndexOptions() != IndexOptions.DOCS;
      hasOffsets |=
          info.getIndexOptions().compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS)
              >= 0;
      hasNorms |= info.hasNorms();
      hasDocValues |= info.getDocValuesType() != DocValuesType.NONE;
      hasPayloads |= info.hasPayloads();
      hasPointValues |= (info.getPointDimensionCount() != 0);
      hasVectorValues |= (info.getVectorDimension() != 0);
      if (info.isSoftDeletesField()) {
        if (softDeletesField != null && softDeletesField.equals(info.name) == false) {
          throw new IllegalArgumentException(
              "multiple soft-deletes fields [" + info.name + ", " + softDeletesField + "]");
        }
        softDeletesField = info.name;
      }
      if (info.isParentField()) {
        if (parentField != null && parentField.equals(info.name) == false) {
          throw new IllegalArgumentException(
              "multiple parent fields [" + info.name + ", " + parentField + "]");
        }
        parentField = info.name;
      }
    }

    this.hasTermVectors = hasTermVectors;
    this.hasPostings = hasPostings;
    this.hasProx = hasProx;
    this.hasPayloads = hasPayloads;
    this.hasOffsets = hasOffsets;
    this.hasFreq = hasFreq;
    this.hasNorms = hasNorms;
    this.hasDocValues = hasDocValues;
    this.hasPointValues = hasPointValues;
    this.hasVectorValues = hasVectorValues;
    this.softDeletesField = softDeletesField;
    this.parentField = parentField;

    if (fieldNumberStrictlyAscending && maxFieldNumber == infos.length - 1) {
      // The input FieldInfo[] contains all fields numbered from 0 to infos.length - 1, and they are
      // sorted, use it directly. This is an optimization when reading a segment with all fields
      // since the FieldInfo[] is sorted.
      byNumber = infos;
      values = Arrays.asList(byNumber);
    } else {
      byNumber = new FieldInfo[maxFieldNumber + 1];
      for (FieldInfo fieldInfo : infos) {
        FieldInfo existing = byNumber[fieldInfo.number];
        if (existing != null) {
          throw new IllegalArgumentException(
              "duplicate field numbers: "
                  + existing.name
                  + " and "
                  + fieldInfo.name
                  + " have: "
                  + fieldInfo.number);
        }
        byNumber[fieldInfo.number] = fieldInfo;
      }
      if (maxFieldNumber == infos.length - 1) {
        // No fields are missing, use byNumber.
        values = Arrays.asList(byNumber);
      } else {
        if (!fieldNumberStrictlyAscending) {
          // The below code is faster than
          // Arrays.stream(byNumber).filter(Objects::nonNull).toList(),
          // mainly when the input FieldInfo[] is small compared to maxFieldNumber.
          Arrays.sort(infos, (fi1, fi2) -> Integer.compare(fi1.number, fi2.number));
        }
        values = Arrays.asList(infos);
      }
    }
  }

  /**
   * Call this to get the (merged) FieldInfos for a composite reader.
   *
   * 

NOTE: the returned field numbers will likely not correspond to the actual field numbers in * the underlying readers, and codec metadata ({@link FieldInfo#getAttribute(String)} will be * unavailable. */ public static FieldInfos getMergedFieldInfos(IndexReader reader) { final List leaves = reader.leaves(); if (leaves.isEmpty()) { return FieldInfos.EMPTY; } else if (leaves.size() == 1) { return leaves.get(0).reader().getFieldInfos(); } else { final String softDeletesField = leaves.stream() .map(l -> l.reader().getFieldInfos().getSoftDeletesField()) .filter(Objects::nonNull) .findAny() .orElse(null); final String parentField = getAndValidateParentField(leaves); final Builder builder = new Builder(new FieldNumbers(softDeletesField, parentField)); for (final LeafReaderContext ctx : leaves) { for (FieldInfo fieldInfo : ctx.reader().getFieldInfos()) { builder.add(fieldInfo); } } return builder.finish(); } } private static String getAndValidateParentField(List leaves) { boolean set = false; String theField = null; for (LeafReaderContext ctx : leaves) { String field = ctx.reader().getFieldInfos().getParentField(); if (set && Objects.equals(field, theField) == false) { throw new IllegalStateException( "expected parent doc field to be \"" + theField + " \" across all segments but found a segment with different field \"" + field + "\""); } else { theField = field; set = true; } } return theField; } /** Returns a set of names of fields that have a terms index. The order is undefined. */ public static Collection getIndexedFields(IndexReader reader) { return reader.leaves().stream() .flatMap( l -> StreamSupport.stream(l.reader().getFieldInfos().spliterator(), false) .filter(fi -> fi.getIndexOptions() != IndexOptions.NONE)) .map(fi -> fi.name) .collect(Collectors.toSet()); } /** Returns true if any fields have freqs */ public boolean hasFreq() { return hasFreq; } /** Returns true if any fields have postings */ public boolean hasPostings() { return hasPostings; } /** Returns true if any fields have positions */ public boolean hasProx() { return hasProx; } /** Returns true if any fields have payloads */ public boolean hasPayloads() { return hasPayloads; } /** Returns true if any fields have offsets */ public boolean hasOffsets() { return hasOffsets; } /** Returns true if any fields have term vectors */ public boolean hasTermVectors() { return hasTermVectors; } /** Returns true if any fields have norms */ public boolean hasNorms() { return hasNorms; } /** Returns true if any fields have DocValues */ public boolean hasDocValues() { return hasDocValues; } /** Returns true if any fields have PointValues */ public boolean hasPointValues() { return hasPointValues; } /** Returns true if any fields have vector values */ public boolean hasVectorValues() { return hasVectorValues; } /** Returns the soft-deletes field name if exists; otherwise returns null */ public String getSoftDeletesField() { return softDeletesField; } /** Returns the parent document field name if exists; otherwise returns null */ public String getParentField() { return parentField; } /** Returns the number of fields */ public int size() { return byName.size(); } /** * Returns an iterator over all the fieldinfo objects present, ordered by ascending field number */ // TODO: what happens if in fact a different order is used? @Override public Iterator iterator() { return values.iterator(); } /** * Return the fieldinfo object referenced by the field name * * @return the FieldInfo object or null when the given fieldName doesn't exist. */ public FieldInfo fieldInfo(String fieldName) { return byName.get(fieldName); } /** * Return the fieldinfo object referenced by the fieldNumber. * * @param fieldNumber field's number. * @return the FieldInfo object or null when the given fieldNumber doesn't exist. * @throws IllegalArgumentException if fieldNumber is negative */ public FieldInfo fieldInfo(int fieldNumber) { if (fieldNumber < 0) { throw new IllegalArgumentException("Illegal field number: " + fieldNumber); } return fieldNumber >= byNumber.length ? null : byNumber[fieldNumber]; } private record FieldDimensions( int dimensionCount, int indexDimensionCount, int dimensionNumBytes) {} private record FieldVectorProperties( int numDimensions, VectorEncoding vectorEncoding, VectorSimilarityFunction similarityFunction) {} private record IndexOptionsProperties(boolean storeTermVectors, boolean omitNorms) {} // We use this to enforce that a given field never // changes DV type, even across segments / IndexWriter // sessions: private record FieldProperties( int number, IndexOptions indexOptions, IndexOptionsProperties indexOptionsProperties, DocValuesType docValuesType, DocValuesSkipIndexType docValuesSkipIndex, FieldDimensions fieldDimensions, FieldVectorProperties fieldVectorProperties) {} static final class FieldNumbers { private final IntObjectHashMap numberToName; private final Map fieldProperties; // TODO: we should similarly catch an attempt to turn // norms back on after they were already committed; today // we silently discard the norm but this is badly trappy private int lowestUnassignedFieldNumber = -1; // The soft-deletes field from IWC to enforce a single soft-deletes field private final String softDeletesFieldName; // The parent document field from IWC to mark parent document when indexing private final String parentFieldName; FieldNumbers(String softDeletesFieldName, String parentFieldName) { this.numberToName = new IntObjectHashMap<>(); this.fieldProperties = new HashMap<>(); this.softDeletesFieldName = softDeletesFieldName; this.parentFieldName = parentFieldName; if (softDeletesFieldName != null && parentFieldName != null && parentFieldName.equals(softDeletesFieldName)) { throw new IllegalArgumentException( "parent document and soft-deletes field can't be the same field \"" + parentFieldName + "\""); } } synchronized void verifyFieldInfo(FieldInfo fi) { String fieldName = fi.getName(); verifySoftDeletedFieldName(fieldName, fi.isSoftDeletesField()); verifyParentFieldName(fieldName, fi.isParentField()); if (fieldProperties.containsKey(fieldName)) { verifySameSchema(fi); } } /** * Returns the global field number for the given field name. If the name does not exist yet it * tries to add it with the given preferred field number assigned if possible otherwise the * first unassigned field number is used as the field number. */ synchronized int addOrGet(FieldInfo fi) { String fieldName = fi.getName(); verifySoftDeletedFieldName(fieldName, fi.isSoftDeletesField()); verifyParentFieldName(fieldName, fi.isParentField()); var fieldProperties = this.fieldProperties.get(fieldName); if (fieldProperties != null) { verifySameSchema(fi); } else { // first time we see this field in this index int fieldNumber; if (fi.number != -1 && numberToName.containsKey(fi.number) == false) { // cool - we can use this number globally fieldNumber = fi.number; } else { // find a new FieldNumber while (numberToName.containsKey(++lowestUnassignedFieldNumber)) { // might not be up to date - lets do the work once needed } fieldNumber = lowestUnassignedFieldNumber; } assert fieldNumber >= 0; numberToName.put(fieldNumber, fieldName); fieldProperties = new FieldProperties( fieldNumber, fi.getIndexOptions(), fi.getIndexOptions() != IndexOptions.NONE ? new IndexOptionsProperties(fi.hasTermVectors(), fi.omitsNorms()) : null, fi.getDocValuesType(), fi.docValuesSkipIndexType(), new FieldDimensions( fi.getPointDimensionCount(), fi.getPointIndexDimensionCount(), fi.getPointNumBytes()), new FieldVectorProperties( fi.getVectorDimension(), fi.getVectorEncoding(), fi.getVectorSimilarityFunction())); this.fieldProperties.put(fieldName, fieldProperties); } return fieldProperties.number; } private void verifySoftDeletedFieldName(String fieldName, boolean isSoftDeletesField) { if (isSoftDeletesField) { if (softDeletesFieldName == null) { throw new IllegalArgumentException( "this index has [" + fieldName + "] as soft-deletes already but soft-deletes field is not configured in IWC"); } else if (fieldName.equals(softDeletesFieldName) == false) { throw new IllegalArgumentException( "cannot configure [" + softDeletesFieldName + "] as soft-deletes; this index uses [" + fieldName + "] as soft-deletes already"); } } else if (fieldName.equals(softDeletesFieldName)) { throw new IllegalArgumentException( "cannot configure [" + softDeletesFieldName + "] as soft-deletes; this index uses [" + fieldName + "] as non-soft-deletes already"); } } private void verifyParentFieldName(String fieldName, boolean isParentField) { if (isParentField) { if (parentFieldName == null) { throw new IllegalArgumentException( "can't add field [" + fieldName + "] as parent document field; this IndexWriter has no parent document field configured"); } else if (fieldName.equals(parentFieldName) == false) { throw new IllegalArgumentException( "can't add field [" + fieldName + "] as parent document field; this IndexWriter is configured with [" + parentFieldName + "] as parent document field"); } } else if (fieldName.equals(parentFieldName)) { // isParent == false // this would be the case if the current index has a parent field that is // not a parent field in the incoming index (think addIndices) throw new IllegalArgumentException( "can't add [" + fieldName + "] as non parent document field; this IndexWriter is configured with [" + parentFieldName + "] as parent document field"); } } private void verifySameSchema(FieldInfo fi) { String fieldName = fi.getName(); FieldProperties fieldProperties = this.fieldProperties.get(fieldName); IndexOptions currentOpts = fieldProperties.indexOptions; verifySameIndexOptions(fieldName, currentOpts, fi.getIndexOptions()); if (currentOpts != IndexOptions.NONE) { boolean curStoreTermVector = fieldProperties.indexOptionsProperties.storeTermVectors; verifySameStoreTermVectors(fieldName, curStoreTermVector, fi.hasTermVectors()); boolean curOmitNorms = fieldProperties.indexOptionsProperties.omitNorms; verifySameOmitNorms(fieldName, curOmitNorms, fi.omitsNorms()); } DocValuesType currentDVType = fieldProperties.docValuesType; verifySameDocValuesType(fieldName, currentDVType, fi.getDocValuesType()); DocValuesSkipIndexType currentDocValuesSkipIndex = fieldProperties.docValuesSkipIndex; verifySameDocValuesSkipIndex( fieldName, currentDocValuesSkipIndex, fi.docValuesSkipIndexType()); FieldDimensions dims = fieldProperties.fieldDimensions; verifySamePointsOptions( fieldName, dims.dimensionCount, dims.indexDimensionCount, dims.dimensionNumBytes, fi.getPointDimensionCount(), fi.getPointIndexDimensionCount(), fi.getPointNumBytes()); FieldVectorProperties props = fieldProperties.fieldVectorProperties; verifySameVectorOptions( fieldName, props.numDimensions, props.vectorEncoding, props.similarityFunction, fi.getVectorDimension(), fi.getVectorEncoding(), fi.getVectorSimilarityFunction()); } /** * This function is called from {@code IndexWriter} to verify if doc values of the field can be * updated. If the field with this name already exists, we verify that it is doc values only * field. If the field doesn't exists and the parameter fieldMustExist is false, we create a new * field in the global field numbers. * * @param fieldName - name of the field * @param dvType - expected doc values type * @param fieldMustExist – if the field must exist. * @throws IllegalArgumentException if the field must exist, but it doesn't, or if the field * exists, but it is not doc values only field with the provided doc values type. */ synchronized void verifyOrCreateDvOnlyField( String fieldName, DocValuesType dvType, boolean fieldMustExist) { if (fieldProperties.containsKey(fieldName) == false) { if (fieldMustExist) { throw new IllegalArgumentException( "Can't update [" + dvType + "] doc values; the field [" + fieldName + "] doesn't exist."); } else { // create dv only field FieldInfo fi = new FieldInfo( fieldName, -1, false, false, false, IndexOptions.NONE, dvType, DocValuesSkipIndexType.NONE, -1, new HashMap<>(), 0, 0, 0, 0, VectorEncoding.FLOAT32, VectorSimilarityFunction.EUCLIDEAN, (softDeletesFieldName != null && softDeletesFieldName.equals(fieldName)), (parentFieldName != null && parentFieldName.equals(fieldName))); addOrGet(fi); } } else { // verify that field is doc values only field with the give doc values type FieldProperties fieldProperties = this.fieldProperties.get(fieldName); DocValuesType fieldDvType = fieldProperties.docValuesType; if (dvType != fieldDvType) { throw new IllegalArgumentException( "Can't update [" + dvType + "] doc values; the field [" + fieldName + "] has inconsistent doc values' type of [" + fieldDvType + "]."); } DocValuesSkipIndexType hasDocValuesSkipIndex = fieldProperties.docValuesSkipIndex; if (hasDocValuesSkipIndex != DocValuesSkipIndexType.NONE) { throw new IllegalArgumentException( "Can't update [" + dvType + "] doc values; the field [" + fieldName + "] must be doc values only field, bit it has doc values skip index"); } FieldDimensions fdimensions = fieldProperties.fieldDimensions; if (fdimensions != null && fdimensions.dimensionCount != 0) { throw new IllegalArgumentException( "Can't update [" + dvType + "] doc values; the field [" + fieldName + "] must be doc values only field, but is also indexed with points."); } IndexOptions ioptions = fieldProperties.indexOptions; if (ioptions != null && ioptions != IndexOptions.NONE) { throw new IllegalArgumentException( "Can't update [" + dvType + "] doc values; the field [" + fieldName + "] must be doc values only field, but is also indexed with postings."); } FieldVectorProperties fvp = fieldProperties.fieldVectorProperties; if (fvp != null && fvp.numDimensions != 0) { throw new IllegalArgumentException( "Can't update [" + dvType + "] doc values; the field [" + fieldName + "] must be doc values only field, but is also indexed with vectors."); } } } /** * Construct a new FieldInfo based on the options in global field numbers. This method is not * synchronized as all the options it uses are not modifiable. * * @param fieldName name of the field * @param dvType doc values type * @param newFieldNumber a new field number * @return {@code null} if {@code fieldName} doesn't exist in the map or is not of the same * {@code dvType} returns a new FieldInfo based based on the options in global field numbers */ FieldInfo constructFieldInfo(String fieldName, DocValuesType dvType, int newFieldNumber) { FieldProperties fieldProperties; synchronized (this) { fieldProperties = this.fieldProperties.get(fieldName); } if (fieldProperties == null) return null; DocValuesType dvType0 = fieldProperties.docValuesType; if (dvType != dvType0) return null; boolean isSoftDeletesField = fieldName.equals(softDeletesFieldName); boolean isParentField = fieldName.equals(parentFieldName); return new FieldInfo( fieldName, newFieldNumber, false, false, false, IndexOptions.NONE, dvType, DocValuesSkipIndexType.NONE, -1, new HashMap<>(), 0, 0, 0, 0, VectorEncoding.FLOAT32, VectorSimilarityFunction.EUCLIDEAN, isSoftDeletesField, isParentField); } synchronized Set getFieldNames() { return Set.copyOf(fieldProperties.keySet()); } synchronized void clear() { numberToName.clear(); fieldProperties.clear(); lowestUnassignedFieldNumber = -1; } } static final class Builder { private final HashMap byName = new HashMap<>(); final FieldNumbers globalFieldNumbers; private boolean finished; /** Creates a new instance with the given {@link FieldNumbers}. */ Builder(FieldNumbers globalFieldNumbers) { assert globalFieldNumbers != null; this.globalFieldNumbers = globalFieldNumbers; } public String getSoftDeletesFieldName() { return globalFieldNumbers.softDeletesFieldName; } /** * Returns the name of the parent document field or null if no parent field is * configured */ public String getParentFieldName() { return globalFieldNumbers.parentFieldName; } /** * Adds the provided FieldInfo to this Builder if this field doesn't exist in this Builder. Also * adds a new field with its schema options to the global FieldNumbers if the field doesn't * exist globally in the index. The field number is reused if possible for consistent field * numbers across segments. * *

If the field already exists: 1) the provided FieldInfo's schema is checked against the * existing field and 2) the provided FieldInfo's attributes are added to the existing * FieldInfo's attributes. * * @param fi – FieldInfo to add * @return The existing FieldInfo if the field with this name already exists in the builder, or * a new constructed FieldInfo with the same schema as provided and a consistent global * field number. * @throws IllegalArgumentException if there already exists field with this name in Builder but * with a different schema * @throws IllegalArgumentException if there already exists field with this name globally but * with a different schema. * @throws IllegalStateException if the Builder is already finished building and doesn't accept * new fields. */ public FieldInfo add(FieldInfo fi) { return add(fi, -1); } /** * Adds the provided FieldInfo with the provided dvGen to this Builder if this field doesn't * exist in this Builder. Also adds a new field with its schema options to the global * FieldNumbers if the field doesn't exist globally in the index. The field number is reused if * possible for consistent field numbers across segments. * *

If the field already exists: 1) the provided FieldInfo's schema is checked against the * existing field and 2) the provided FieldInfo's attributes are added to the existing * FieldInfo's attributes. * * @param fi – FieldInfo to add * @param dvGen – doc values generation of the FieldInfo to add * @return The existing FieldInfo if the field with this name already exists in the builder, or * a new constructed FieldInfo with the same schema as provided and a consistent global * field number. * @throws IllegalArgumentException if there already exists field with this name in Builder but * with a different schema * @throws IllegalArgumentException if there already exists field with this name globally but * with a different schema. * @throws IllegalStateException if the Builder is already finished building and doesn't accept * new fields. */ FieldInfo add(FieldInfo fi, long dvGen) { final FieldInfo curFi = fieldInfo(fi.getName()); if (curFi != null) { curFi.verifySameSchema(fi); if (fi.attributes() != null) { fi.attributes().forEach((k, v) -> curFi.putAttribute(k, v)); } if (fi.hasPayloads()) { curFi.setStorePayloads(); } return curFi; } // This field wasn't yet added to this in-RAM segment's FieldInfo, // so now we get a global number for this field. // If the field was seen before then we'll get the same name and number, // else we'll allocate a new one assert assertNotFinished(); final int fieldNumber = globalFieldNumbers.addOrGet(fi); FieldInfo fiNew = new FieldInfo( fi.getName(), fieldNumber, fi.hasTermVectors(), fi.omitsNorms(), fi.hasPayloads(), fi.getIndexOptions(), fi.getDocValuesType(), fi.docValuesSkipIndexType(), dvGen, // original attributes is UnmodifiableMap new HashMap<>(fi.attributes()), fi.getPointDimensionCount(), fi.getPointIndexDimensionCount(), fi.getPointNumBytes(), fi.getVectorDimension(), fi.getVectorEncoding(), fi.getVectorSimilarityFunction(), fi.isSoftDeletesField(), fi.isParentField()); byName.put(fiNew.getName(), fiNew); return fiNew; } public FieldInfo fieldInfo(String fieldName) { return byName.get(fieldName); } /** Called only from assert */ private boolean assertNotFinished() { if (finished) { throw new IllegalStateException( "FieldInfos.Builder was already finished; cannot add new fields"); } return true; } FieldInfos finish() { finished = true; return new FieldInfos(byName.values().toArray(new FieldInfo[byName.size()])); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy