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

com.google.appengine.api.search.dev.FieldExpression Maven / Gradle / Ivy

Go to download

SDK for dev_appserver (local development) with some of the dependencies shaded (repackaged)

There is a newer version: 2.0.31
Show newest version
/*
 * Copyright 2021 Google LLC
 *
 * 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
 *
 *     https://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 com.google.appengine.api.search.dev;

import com.google.apphosting.api.search.DocumentPb.FieldValue;
import com.google.apphosting.api.search.DocumentPb.FieldValue.ContentType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.appengine.repackaged.org.apache.lucene.document.Document;
import com.google.appengine.repackaged.org.apache.lucene.document.Field;

/**
 * Expression which evalutes to the content of a field.
 *
 */
public class FieldExpression extends NumericExpression {
  private final Map luceneFields;
  private final List typePriority;
  private final List typePriorityWithoutNumeric;
  private final boolean hasNumericFields;

  public FieldExpression(String fieldName, Set fieldTypes) {
    this.luceneFields = new HashMap(fieldTypes.size());
    this.typePriority = new ArrayList(fieldTypes.size());
    this.typePriorityWithoutNumeric = new ArrayList(fieldTypes.size());

    for (ContentType type : fieldTypes) {
      this.luceneFields.put(type, LuceneUtils.makeLuceneFieldName(fieldName, type));
    }
    for (ContentType type : new ContentType[] {ContentType.NUMBER, ContentType.DATE,
        ContentType.TEXT, ContentType.HTML, ContentType.ATOM}) {
      if (fieldTypes.contains(type)) {
        this.typePriority.add(type);
      }
    }
    for (ContentType type : new ContentType[] {ContentType.DATE, ContentType.TEXT,
        ContentType.HTML, ContentType.ATOM}) {
      if (fieldTypes.contains(type)) {
        this.typePriorityWithoutNumeric.add(type);
      }
    }
    hasNumericFields =
        fieldTypes.contains(ContentType.NUMBER) || fieldTypes.contains(ContentType.DATE);
  }

  public static FieldExpression makeFieldExpression(String fieldName, Set fieldTypes) {
    if (fieldTypes == null) {
      throw new IllegalArgumentException("Unknown field:" + fieldName);
    }
    return new FieldExpression(fieldName, fieldTypes);
  }

  @Override
  public double evalDouble(Document doc) throws EvaluationException {
    String luceneFieldName = luceneFields.get(ContentType.NUMBER);
    if (luceneFieldName == null) {
      luceneFieldName = luceneFields.get(ContentType.DATE);
      if (luceneFieldName == null) {
        throw new EvaluationException("incorrect field type");
      }
    }
    Field[] fields = doc.getFields(luceneFieldName);
    if (fields.length == 0) {
      throw new EvaluationException("numeric field was not found");
    }
    return LuceneUtils.numericFieldToDouble(fields[0]);
  }

  @Override
  public FieldValue eval(Document doc) throws EvaluationException {
    return evalWithTypePriority(doc, typePriority);
  }

  public FieldValue evalWithTypePriority(Document doc, List typePriority)
      throws EvaluationException {
    for (ContentType type : typePriority) {
      String fieldName = luceneFields.get(type);
      Field[] fields = doc.getFields(fieldName);
      if (fields.length == 0) {
        continue;
      }
      String stringValue = String.valueOf(LuceneUtils.luceneFieldToValue(fields[0], type));
      if (type == ContentType.TEXT || type == ContentType.ATOM) {
        type = ContentType.HTML;
      }
      return makeValue(type, stringValue);
    }
    throw new EvaluationException("field was not found");
  }

  void checkType(ContentType type) {
    if (luceneFields.get(type) == null) {
      throw new IllegalArgumentException("Field type mismatch");
    }
  }

  /**
   * @return at most 2 sorters. First, special case for numberic fields.
   * Second, alpha-numerical sort for other field types.
   */
  @Override
  public List getSorters(final int sign, double defaultValueNumeric,
      final String defaultValueText) {
    List sorters = new ArrayList(1);

    if (hasNumericFields) {
      sorters.add(getNumericSorter(sign, defaultValueNumeric));
    }
    if (!typePriorityWithoutNumeric.isEmpty()) {
      sorters.add(new Sorter() {
        @Override
        public Object eval(Document doc) {
          try {
            return evalWithTypePriority(doc, typePriorityWithoutNumeric).getStringValue();
          } catch (EvaluationException e) {
            return defaultValueText;
          }
        }

        @Override
        public int compare(Object left, Object right) {
          String leftString = (String) left;
          String rightString = (String) right;
          return sign * leftString.compareToIgnoreCase(rightString);
        }
      });
    }
    return sorters;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy