Package com.datasalt.pangool.tuplemr

Source Code of com.datasalt.pangool.tuplemr.OrderBy

/**
* Copyright [2012] [Datasalt Systems S.L.]
*
* 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 com.datasalt.pangool.tuplemr;

import com.datasalt.pangool.PangoolRuntimeException;
import com.datasalt.pangool.tuplemr.Criteria.NullOrder;
import com.datasalt.pangool.tuplemr.Criteria.Order;
import com.datasalt.pangool.tuplemr.Criteria.SortElement;
import org.apache.hadoop.io.RawComparator;
import org.codehaus.jackson.map.ObjectMapper;

import java.util.ArrayList;
import java.util.List;

/**
* OrderBy is a convenience builder used by {@link TupleMRConfig} , similar to
* {@link Criteria}. The main difference is that {@link OrderBy} is mutable
* using the concatenation pattern and allows to specify schemaOrder.
* <p/>
* The OrderBy instances are converted to immutable Criteria objects by
* {@link TupleMRConfig}.
*/
public class OrderBy {

  private Order schemaOrder;
  private Integer schemaOrderIndex;
  private List<SortElement> elements = new ArrayList<SortElement>();

  public OrderBy(List<SortElement> elements) {
    this.elements = elements;
  }

  public OrderBy() {
  }

  /**
   * Parse in the form "field1:asc, field2:desc,...,fieldn:asc|null_smallest"
   * <br/>
   * Examples:
   * <br/>
   * "f1,f2,f3"
   * <br/>
   * "f1:asc,f2:desc,f3"
   * <br/>
   * "f1,f2:asc|null_smallest,f3:desc|null_biggest"
   */
  public static OrderBy parse(String orderBy) {
    OrderBy toReturn = new OrderBy();
    String[] orderBys = orderBy.split(",");
    for (String order : orderBys) {
      order = order.trim();
      String[] fields = order.split(":");
      Order ord = Order.ASC;
      NullOrder nullOrd = NullOrder.NULL_SMALLEST;
      if (fields.length > 1) {
        String[] qualifiers = fields[1].split("\\|");
        for (String qualifier : qualifiers) {
          qualifier = qualifier.trim();
          boolean success = false;
          try {
            ord = Order.valueOf(qualifier.toUpperCase());
            success = true;
          } catch (IllegalArgumentException e) {
          }
          try {
            nullOrd = NullOrder.valueOf(qualifier.toUpperCase());
            success = true;
          } catch (IllegalArgumentException e) {
          }
          if (!success) {
            throw new PangoolRuntimeException("Unrecognised sort qualifier " + qualifier +
                " on sorting string: " + orderBy + ". Valid qualifiers are " + validQualifiers());
          }
        }
      }
      toReturn.add(fields[0].trim(), ord, nullOrd);
    }
    return toReturn;
  }

  private static String validQualifiers() {
    String ret = "";
    boolean first = true;
    for (Order o : Order.values()) {
      if (!first) {
        ret += ",";
      }
      ret += o;
      first = false;
    }
    ret += ",";
    first = true;
    for (NullOrder o : NullOrder.values()) {
      if (!first) {
        ret += ",";
      }
      ret += o;
      first = false;
    }
    return ret;
  }

  /**
   * Adds a new field to order by and its specified order.
   * <br/>
   * The default @{link NullOrder} used is for nullable fields is @{link NullOrder#NULL_SMALLEST}
   *
   * @param name  Field's name
   * @param order Field's order
   * @see Order
   */
  public OrderBy add(String name, Order order) {
    failIfFieldNamePresent(name);
    this.elements.add(new SortElement(name, order, NullOrder.NULL_SMALLEST));
    return this;
  }

  /**
   * Adds a new field to order by and its specified order.
   *
   * @param name      Field's name
   * @param order     Field's order
   * @param nullOrder Sorting of null values in nullable fields. {@link NullOrder#NULL_SMALLEST} if you want
   *                  nulls to be the smallest value or {@link NullOrder#NULL_BIGGEST} if you want
   *                  nulls to be the biggest. Ignored if fields are not nullable. Cannot be null.
   * @see Order
   * @see NullOrder
   */
  public OrderBy add(String name, Order order, NullOrder nullOrder) {
    failIfFieldNamePresent(name);
    this.elements.add(new SortElement(name, order, nullOrder));
    return this;
  }

  /**
   * Same as {@link OrderBy#add(String, Order)} but adding the possibility to
   * specify a custom comparator for that field.
   *
   * @param name       Field's name
   * @param order      Field's order
   * @param nullOrder  Sorting of null values in nullable fields. {@link NullOrder#NULL_SMALLEST} if you want
   *                   nulls to be the smallest value or {@link NullOrder#NULL_BIGGEST} if you want
   *                   nulls to be the biggest. Ignored if fields are not nullable. Cannot be null.
   * @param comparator Custom comparator instance
   * @see Order
   * @see NullOrder
   */
  public OrderBy add(String name, Order order, NullOrder nullOrder, RawComparator<?> comparator) {
    failIfFieldNamePresent(name);
    this.elements.add(new SortElement(name, order, nullOrder, comparator));
    return this;
  }


  /**
   * This method,unlike the traditional
   * {@link OrderBy#add(String, Order, NullOrder, RawComparator)} method, adds a symbolic
   * elements to order by.<p>
   * <p/>
   * This method only works in a multi-schema scenario, and it specifies that
   * tuples will be sorted by their schema,not by a field's name.<br>
   * <p/>
   * Example :<br>
   * b.addIntermediateSchema(schema1); b.addIntermediateSchema(schema2);<br>
   * b.setOrderBy(new OrderBy().add("user_id",Order.ASC).addSchemaOrder(Order.DESC));</br>
   * <p/>
   * In the case above, tuples will be first sorted by user_id and then if they
   * compare as equals then tuples from schema2 will sort before those from
   * schema1.
   * <p/>
   * This method must be called just once, and it's not allowed in
   * {@link TupleMRConfigBuilder#setSpecificOrderBy(String, OrderBy)}
   */
  public OrderBy addSchemaOrder(Order order) {
    if (this.schemaOrderIndex != null) {
      throw new IllegalStateException("The schema order is already set");
    }
    this.schemaOrder = order;
    this.schemaOrderIndex = getElements().size();
    return this;
  }

  /**
   * Returns a {@link SortElement} object for every field added to this builder.
   *
   * @see SortElement
   */
  public List<SortElement> getElements() {
    return elements;
  }

  /**
   * Gets the schemaOrder if set.
   */
  public Order getSchemaOrder() {
    return schemaOrder;
  }

  /**
   * Returns the position in the list where schemaOrder was added using
   * {@link OrderBy#addSchemaOrder(Order)}
   */
  public Integer getSchemaOrderIndex() {
    return schemaOrderIndex;
  }

  private void failIfFieldNamePresent(String name) {
    if (containsFieldName(name)) {
      throw new IllegalArgumentException("Sort element with field name '" + name
          + "' is already present");
    }
  }

  /**
   * True if field was added using {@link #add(String, Order)}
   */
  public boolean containsFieldName(String field) {
    for (SortElement e : elements) {
      if (e.getName().equals(field)) {
        return true;
      }
    }
    return false;
  }

  /**
   * True if field was added before calling {@link #addSchemaOrder(Order)}
   */
  public boolean containsBeforeSchemaOrder(String field) {
    if (schemaOrderIndex == null) {
      return containsFieldName(field);
    }
    for (int i = 0; i < schemaOrderIndex; i++) {
      if (elements.get(i).getName().equals(field)) {
        return true;
      }
    }
    return false;
  }

  public String toString() {
    ObjectMapper mapper = new ObjectMapper();

    try {
      return mapper.writeValueAsString(elements);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
}
TOP

Related Classes of com.datasalt.pangool.tuplemr.OrderBy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.