| /* |
| * 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.solr.schema; |
| |
| import java.lang.invoke.MethodHandles; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Locale; |
| |
| import org.apache.lucene.document.NumericDocValuesField; |
| import org.apache.lucene.document.SortedSetDocValuesField; |
| import org.apache.lucene.index.IndexableField; |
| import org.apache.solr.legacy.LegacyFieldType; |
| import org.apache.solr.legacy.LegacyIntField; |
| import org.apache.solr.legacy.LegacyNumericRangeQuery; |
| import org.apache.solr.legacy.LegacyNumericType; |
| import org.apache.solr.legacy.LegacyNumericUtils; |
| import org.apache.lucene.search.ConstantScoreQuery; |
| import org.apache.lucene.search.Query; |
| import org.apache.lucene.util.BytesRef; |
| import org.apache.lucene.util.BytesRefBuilder; |
| import org.apache.lucene.util.CharsRef; |
| import org.apache.lucene.util.CharsRefBuilder; |
| import org.apache.solr.common.EnumFieldValue; |
| import org.apache.solr.common.SolrException; |
| import org.apache.solr.search.QParser; |
| import org.apache.solr.uninverting.UninvertingReader.Type; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * Field type for support of string values with custom sort order. |
| * @deprecated use {@link EnumFieldType} instead. |
| */ |
| @Deprecated |
| public class EnumField extends AbstractEnumField { |
| |
| private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); |
| protected static final int DEFAULT_PRECISION_STEP = Integer.MAX_VALUE; |
| |
| @Override |
| public Type getUninversionType(SchemaField sf) { |
| if (sf.multiValued()) { |
| return Type.SORTED_SET_INTEGER; |
| } else { |
| return Type.LEGACY_INTEGER; |
| } |
| } |
| |
| @Override |
| protected Query getSpecializedRangeQuery(QParser parser, SchemaField field, String min, String max, boolean minInclusive, boolean maxInclusive) { |
| Integer minValue = enumMapping.stringValueToIntValue(min); |
| Integer maxValue = enumMapping.stringValueToIntValue(max); |
| |
| if (field.multiValued() && field.hasDocValues() && !field.indexed()) { |
| // for the multi-valued dv-case, the default rangeimpl over toInternal is correct |
| return super.getSpecializedRangeQuery(parser, field, minValue.toString(), maxValue.toString(), minInclusive, maxInclusive); |
| } |
| Query query = null; |
| final boolean matchOnly = field.hasDocValues() && !field.indexed(); |
| if (matchOnly) { |
| long lowerValue = Long.MIN_VALUE; |
| long upperValue = Long.MAX_VALUE; |
| if (minValue != null) { |
| lowerValue = minValue.longValue(); |
| if (minInclusive == false) { |
| ++lowerValue; |
| } |
| } |
| if (maxValue != null) { |
| upperValue = maxValue.longValue(); |
| if (maxInclusive == false) { |
| --upperValue; |
| } |
| } |
| query = new ConstantScoreQuery(NumericDocValuesField.newSlowRangeQuery(field.getName(), lowerValue, upperValue)); |
| } else { |
| query = LegacyNumericRangeQuery.newIntRange(field.getName(), DEFAULT_PRECISION_STEP, |
| min == null ? null : minValue, |
| max == null ? null : maxValue, |
| minInclusive, maxInclusive); |
| } |
| |
| return query; |
| } |
| |
| @Override |
| public void readableToIndexed(CharSequence val, BytesRefBuilder result) { |
| final String s = val.toString(); |
| if (s == null) |
| return; |
| |
| final Integer intValue = enumMapping.stringValueToIntValue(s); |
| LegacyNumericUtils.intToPrefixCoded(intValue, 0, result); |
| } |
| |
| @Override |
| public String indexedToReadable(String indexedForm) { |
| if (indexedForm == null) |
| return null; |
| final BytesRef bytesRef = new BytesRef(indexedForm); |
| final Integer intValue = LegacyNumericUtils.prefixCodedToInt(bytesRef); |
| return enumMapping.intValueToStringValue(intValue); |
| } |
| |
| @Override |
| public CharsRef indexedToReadable(BytesRef input, CharsRefBuilder output) { |
| final Integer intValue = LegacyNumericUtils.prefixCodedToInt(input); |
| final String stringValue = enumMapping.intValueToStringValue(intValue); |
| output.grow(stringValue.length()); |
| output.setLength(stringValue.length()); |
| stringValue.getChars(0, output.length(), output.chars(), 0); |
| return output.get(); |
| } |
| |
| @Override |
| public EnumFieldValue toObject(SchemaField sf, BytesRef term) { |
| final Integer intValue = LegacyNumericUtils.prefixCodedToInt(term); |
| final String stringValue = enumMapping.intValueToStringValue(intValue); |
| return new EnumFieldValue(intValue, stringValue); |
| } |
| |
| @Override |
| public String storedToIndexed(IndexableField f) { |
| final Number val = f.numericValue(); |
| if (val == null) |
| return null; |
| final BytesRefBuilder bytes = new BytesRefBuilder(); |
| LegacyNumericUtils.intToPrefixCoded(val.intValue(), 0, bytes); |
| return bytes.get().utf8ToString(); |
| } |
| |
| @Override |
| public IndexableField createField(SchemaField field, Object value) { |
| final boolean indexed = field.indexed(); |
| final boolean stored = field.stored(); |
| final boolean docValues = field.hasDocValues(); |
| |
| if (!indexed && !stored && !docValues) { |
| if (log.isTraceEnabled()) |
| log.trace("Ignoring unindexed/unstored field: {}", field); |
| return null; |
| } |
| final Integer intValue = enumMapping.stringValueToIntValue(value.toString()); |
| if (intValue == null || intValue.equals(EnumMapping.DEFAULT_VALUE)) { |
| String exceptionMessage = String.format(Locale.ENGLISH, "Unknown value for enum field: %s, value: %s", |
| field.getName(), value.toString()); |
| throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, exceptionMessage); |
| } |
| |
| final LegacyFieldType newType = new LegacyFieldType(); |
| |
| newType.setTokenized(field.isTokenized()); |
| newType.setStored(field.stored()); |
| newType.setOmitNorms(field.omitNorms()); |
| newType.setIndexOptions(field.indexOptions()); |
| newType.setStoreTermVectors(field.storeTermVector()); |
| newType.setStoreTermVectorOffsets(field.storeTermOffsets()); |
| newType.setStoreTermVectorPositions(field.storeTermPositions()); |
| newType.setStoreTermVectorPayloads(field.storeTermPayloads()); |
| newType.setNumericType(LegacyNumericType.INT); |
| newType.setNumericPrecisionStep(DEFAULT_PRECISION_STEP); |
| |
| return new LegacyIntField(field.getName(), intValue.intValue(), newType); |
| } |
| |
| @Override |
| public List<IndexableField> createFields(SchemaField sf, Object value) { |
| if (sf.hasDocValues()) { |
| List<IndexableField> fields = new ArrayList<>(); |
| final IndexableField field = createField(sf, value); |
| fields.add(field); |
| |
| if (sf.multiValued()) { |
| BytesRefBuilder bytes = new BytesRefBuilder(); |
| readableToIndexed(enumMapping.stringValueToIntValue(value.toString()).toString(), bytes); |
| fields.add(new SortedSetDocValuesField(sf.getName(), bytes.toBytesRef())); |
| } else { |
| final long bits = field.numericValue().intValue(); |
| fields.add(new NumericDocValuesField(sf.getName(), bits)); |
| } |
| return fields; |
| } else { |
| return Collections.singletonList(createField(sf, value)); |
| } |
| } |
| } |