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

org.pageseeder.flint.lucene.query.DateParameter Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2015 Allette Systems (Australia)
 * http://www.allette.com.au
 *
 * 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.
 */
package org.pageseeder.flint.lucene.query;

import org.apache.lucene.document.DateTools.Resolution;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.util.BytesRef;
import org.pageseeder.flint.lucene.util.Dates;
import org.pageseeder.xmlwriter.XMLWriter;

import java.io.IOException;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Date;

/**
 * Create a date range parameter.
 *
 * @author Christophe Lauret (Weborganic)
 * @author Jean-Baptiste Reure (Weborganic)
 *
 * @version 10 September 2010
 */
public final class DateParameter implements SearchParameter {

  /**
   * The date field.
   */
  private final String _field;

  /**
   * The FROM date, if null, then no lower limit.
   */
  private final OffsetDateTime _from;

  /**
   * The TO date, if null, then no upper limit.
   */
  private final OffsetDateTime _to;

  /**
   * The resolution for this date field.
   */
  private final Resolution _resolution;

  /**
   * Whether the minimum value should be included; ignored if the minimum value is null
   */
  private final boolean _minInclusive;

  /**
   * Whether the maximum value should be included; ignored if the maximum value is null
   */
  private final boolean _maxInclusive;

  /**
   * Indicates whether the date field is a numeric field.
   */
  private final boolean _numeric;

  /**
   * The actual Lucene query (lazy initialised)
   */
  private volatile Query _query;

// Implementation methods ----------------------------------------------------------------------

  /**
   * Creates a new date parameter matching empty values.
   *
   * @param field      the date field to search
   * @param resolution the date resolution
   * @param numeric    whether it is a numeric field
   */
  public DateParameter(String field, Resolution resolution, boolean numeric) {
    this(field, null, (OffsetDateTime) null, true, true, resolution, numeric);
  }

  /**
   * Creates a new date parameter.
   *
   * @param field      the date field to search
   * @param exactMatch the exact matching date
   * @param resolution the date resolution
   * @param numeric    whether it is a numeric field
   */
  public DateParameter(String field, Date exactMatch, Resolution resolution, boolean numeric) {
    this(field, exactMatch, exactMatch, true, true, resolution, numeric);
  }

  /**
   * Creates a new date parameter (inclusive of from and to dates).
   *
   * @param field      the date field to search
   * @param from       the start date in the range (can be null)
   * @param to         the end date in the range (can be null)
   * @param resolution the date resolution
   * @param numeric    whether it is a numeric field
   */
  public DateParameter(String field, Date from, Date to, Resolution resolution, boolean numeric) {
    this(field, from, to, true, true, resolution, numeric);
  }

  /**
   * Creates a new date parameter.
   *
   * @param field      the date field to search
   * @param from       the start date in the range (can be null)
   * @param to         the end date in the range (can be null)
   * @param withMin    if the 'from' date is included in the range
   * @param withMax    if the 'to' date is included in the range
   * @param resolution the date resolution
   * @param numeric    whether it is a numeric field
   */
  public DateParameter(String field, Date from, Date to, boolean withMin, boolean withMax, Resolution resolution, boolean numeric) {
    this(field, from == null ? null : OffsetDateTime.ofInstant(Instant.ofEpochMilli(from.getTime()), ZoneOffset.UTC),
                to   == null ? null : OffsetDateTime.ofInstant(Instant.ofEpochMilli(to.getTime()),   ZoneOffset.UTC), withMin, withMax, resolution, numeric);
  }

  /**
   * Creates a new date parameter.
   *
   * @param field      the date field to search
   * @param exactMatch the exact matching date
   * @param resolution the date resolution
   * @param numeric    whether it is a numeric field
   */
  public DateParameter(String field, OffsetDateTime exactMatch, Resolution resolution, boolean numeric) {
    this(field, exactMatch, exactMatch, true, true, resolution, numeric);
  }

  /**
   * Creates a new date parameter (inclusive of from and to dates).
   *
   * @param field      the date field to search
   * @param from       the start date in the range (can be null)
   * @param to         the end date in the range (can be null)
   * @param resolution the date resolution
   * @param numeric    whether it is a numeric field
   */
  public DateParameter(String field, OffsetDateTime from, OffsetDateTime to, Resolution resolution, boolean numeric) {
    this(field, from, to, true, true, resolution, numeric);
  }

  /**
   * Creates a new date parameter.
   *
   * @param field      the date field to search
   * @param from       the start date in the range (can be null)
   * @param to         the end date in the range (can be null)
   * @param withMin    if the 'from' date is included in the range
   * @param withMax    if the 'to' date is included in the range
   * @param resolution the date resolution
   * @param numeric    whether it is a numeric field
   */
  public DateParameter(String field, OffsetDateTime from, OffsetDateTime to, boolean withMin, boolean withMax, Resolution resolution, boolean numeric) {
    if (field == null) throw new NullPointerException("field");
    if (resolution == null) throw new NullPointerException("resolution");
    this._field = field;
    this._from = from;
    this._to = to;
    this._minInclusive = withMin;
    this._maxInclusive = withMax;
    this._resolution = resolution;
    this._numeric = numeric;
  }

  /**
   * Returns the value of the lower limit of the date range.
   *
   * @return A date instance or null.
   */
  public Date from() {
    return this._from != null? new Date(this._from.toInstant().toEpochMilli()) : null;
  }

  /**
   * Returns the value of the upper limit for the date range.
   *
   * @return A date instance  or null.
   */
  public Date to() {
    return this._to != null? new Date(this._to.toInstant().toEpochMilli()) : null;
  }

  /**
   * Returns the value of the lower limit of the date range.
   *
   * @return A date instance or null.
   */
  public OffsetDateTime fromOffsetDateTime() {
    return this._from;
  }

  /**
   * Returns the value of the upper limit for the date range.
   *
   * @return A date instance or null.
   */
  public OffsetDateTime toOffsetDateTime() {
    return this._to;
 }

  /**
   * Returns the name of the date field to search.
   *
   * @return The name of the date field to search.
   */
  public String field() {
    return this._field;
  }

  /**
   * Returns true if this search query does not contain any parameter.
   *
   * @return true if this search query does not contain any parameter;
   *         false otherwise.
   */
  @Override
  public boolean isEmpty() {
    return this._from == null && this._to == null;
  }

  public boolean isMaxIncluded() {
    return this._maxInclusive;
  }

  public boolean isMinIncluded() {
    return this._minInclusive;
  }

  /**
   * Generates the Query object corresponding to a date range search query.
   * 

* Returns a TermRangeQuery or a NumericRangeQuery based on the values in this object. * * @return a TermRangeQuery, a NumericRangeQuery or null if empty. */ @Override public Query toQuery() { // an including range query on the date if (this._query == null) { if (this._from == null && this._to == null) { this._query = new TermQuery(new Term(this._field, "")); } else if (this._numeric) { this._query = toNumericRangeQuery(this._field, this._from, this._to, this._minInclusive, this._maxInclusive, this._resolution); } else { this._query = toTermRangeQuery(this._field, this._from, this._to, this._minInclusive, this._maxInclusive, this._resolution); } } return this._query; } /** * Serialises the search query as XML. * * @param xml The XML writer. * * @throws IOException Should there be any I/O exception while writing the XML. */ @Override public void toXML(XMLWriter xml) throws IOException { boolean exactMatch = this._from != null && this._from.equals(this._to); xml.openElement(exactMatch ? "date-parameter" : "date-range", false); xml.attribute("field", this._field); if (this._from == null && this._to == null) { xml.attribute("value", ""); } else if (exactMatch) { xml.attribute("value", Dates.format(this._from, this._resolution)); } else { if (this._from != null) { xml.attribute("from", Dates.format(this._from, this._resolution)); xml.attribute("from-included", Boolean.toString(this._minInclusive)); } if (this._to != null) { xml.attribute("to", Dates.format(this._to, this._resolution)); xml.attribute("to-included", Boolean.toString(this._maxInclusive)); } } xml.closeElement(); } @Override public String toString() { Query q = toQuery(); return q == null ? "[empty]" : q.toString(); } // Private helpers ------------------------------------------------------------------------------ /** * Returns the term range query that corresponds to the specified parameters. * * @param field the date field * @param from the lower limit (can be null) * @param to the upper limit (can be null) * @param resolution the date resolution in use * * @return the corresponding TermRangeQuery */ private static TermRangeQuery toTermRangeQuery(String field, OffsetDateTime from, OffsetDateTime to, boolean withMin, boolean withMax, Resolution resolution) { BytesRef min = from != null? new BytesRef(Dates.toString(from, resolution).getBytes()) : null; BytesRef max = to != null? new BytesRef(Dates.toString(to, resolution).getBytes()) : null; return new TermRangeQuery(field, min, max, withMin, withMax); } /** * Returns the term range query that corresponds to the specified parameters. * * @param field the date field * @param from the lower limit (can be null) * @param to the upper limit (can be null) * @param resolution the date resolution in use * * @return the corresponding NumericRangeQuery */ private static Query toNumericRangeQuery(String field, OffsetDateTime from, OffsetDateTime to, boolean withMin, boolean withMax, Resolution resolution) { Number min = from != null ? Dates.toNumber(from, resolution) : null; Number max = to != null ? Dates.toNumber(to, resolution) : null; // Using long values (resolution = MILLISECOND | SECOND | MINUTE | HOUR) if (min instanceof Long || (min == null && max instanceof Long)) { long minLong = min == null ? Long.MIN_VALUE : withMin ? (Long) min : Math.addExact((Long) min, -1); long maxLong = max == null ? Long.MAX_VALUE : withMax ? (Long) max : Math.addExact((Long) max, 1); return LongPoint.newRangeQuery(field, minLong, maxLong); } // Using integer values (resolution = DAY | MONTH | YEAR) if (min instanceof Integer || (min == null && max instanceof Integer)) { int minLong = min == null ? Integer.MIN_VALUE : withMin ? (Integer) min : Math.addExact((Integer) min, 1); int maxLong = max == null ? Integer.MAX_VALUE : withMax ? (Integer) max : Math.addExact((Integer) max, -1); return IntPoint.newRangeQuery(field, minLong, maxLong); } // Should never happen return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy