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

org.cloudgraph.hbase.scan.ScanCollector Maven / Gradle / Ivy

Go to download

CloudGraph(tm) is a suite of Service Data Object (SDO) 2.1 services designed for relational and big-table style "cloud" databases, such as HBase and others.

There is a newer version: 2.0.4
Show newest version
/**
 *        CloudGraph Community Edition (CE) License
 * 
 * This is a community release of CloudGraph, a dual-license suite of
 * Service Data Object (SDO) 2.1 services designed for relational and 
 * big-table style "cloud" databases, such as HBase and others. 
 * This particular copy of the software is released under the 
 * version 2 of the GNU General Public License. CloudGraph was developed by 
 * TerraMeta Software, Inc.
 * 
 * Copyright (c) 2013, TerraMeta Software, Inc. All rights reserved.
 * 
 * General License information can be found below.
 * 
 * This distribution may include materials developed by third
 * parties. For license and attribution notices for these
 * materials, please refer to the documentation that accompanies
 * this distribution (see the "Licenses for Third-Party Components"
 * appendix) or view the online documentation at 
 * . 
 */
package org.cloudgraph.hbase.scan;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudgraph.config.CloudGraphConfig;
import org.cloudgraph.config.DataGraphConfig;
import org.cloudgraph.config.UserDefinedRowKeyFieldConfig;
import org.cloudgraph.query.expr.Expr;
import org.cloudgraph.query.expr.ExprVisitor;
import org.cloudgraph.query.expr.LogicalBinaryExpr;
import org.cloudgraph.query.expr.RelationalBinaryExpr;
import org.cloudgraph.query.expr.WildcardBinaryExpr;
import org.plasma.query.model.LogicalOperatorValues;
import org.plasma.query.model.RelationalOperatorValues;
import org.plasma.sdo.PlasmaProperty;
import org.plasma.sdo.PlasmaType;

/**
 * Collector visitor which supports the "recognition" of one or more 
 * {@link PartialRowKey partial}, {@link FuzzyRowKey fuzzy} and other
 * scan constructs within the context of a binary (query) 
 * {@link Expr expression} syntax tree, encapsulating operator precedence
 * and other factors. 
 * 

* Composite row key scans represent only {@link org.cloudgraph.hbase.expr.LogicalBinaryExpr logical binary} 'AND' * expressions across the key fields. So * for {@link org.cloudgraph.hbase.expr.RelationalBinaryExpr relational binary} expressions * linked within a query syntax tree by one or more logical binary 'AND', * expressions, a single {@link PartialRowKey partial} or {@link FuzzyRowKey fuzzy} * row key scan may be used. But for {@link org.cloudgraph.hbase.expr.RelationalBinaryExpr relational binary} expressions * linked by {@link org.cloudgraph.hbase.expr.LogicalBinaryExpr logical binary} 'OR' expressions * multiple scans must be used. Clients of this collector class may execute the * resulting scans in series or in parallel depending on various performance * and other considerations. *

* @author Scott Cinnamond * @since 0.5.3 * @see org.cloudgraph.hbase.expr.Expr * @see org.cloudgraph.hbase.expr.BinaryExpr * @see org.cloudgraph.hbase.expr.ExprVisitor * @see org.cloudgraph.config.DataGraphConfig * @see org.cloudgraph.hbase.expr.LogicalBinaryExpr * @see org.cloudgraph.hbase.expr.RelationalBinaryExpr * @see org.cloudgraph.hbase.expr.WildcardBinaryExpr */ public class ScanCollector implements ExprVisitor { private static Log log = LogFactory.getLog(ScanCollector.class); private List>> literals = new ArrayList>>(); private PlasmaType rootType; private DataGraphConfig graph; private List partialKeyScans; private List fuzzyKeyScans; private List completeKeys; private ScanLiteralFactory factory = new ScanLiteralFactory(); private boolean queryRequiresGraphRecognizer = false; public ScanCollector(PlasmaType rootType) { this.rootType = rootType; QName rootTypeQname = this.rootType.getQualifiedName(); this.graph = CloudGraphConfig.getInstance().getDataGraph( rootTypeQname); } private void init() { if (this.partialKeyScans == null) { this.partialKeyScans = new ArrayList(this.literals.size()); this.fuzzyKeyScans = new ArrayList(this.literals.size()); this.completeKeys = new ArrayList(this.literals.size()); for (Map> existing : this.literals) { ScanLiterals scanLiterals = new ScanLiterals(); for (List literalList : existing.values()) { for (ScanLiteral literal : literalList) scanLiterals.addLiteral(literal); } // gives precedence to complete keys over partial keys and to partial // keys over fuzzy keys if (scanLiterals.supportCompleteRowKey(this.graph)) { CompleteRowKeyAssembler assembler = new CompleteRowKeyAssembler(this.rootType); assembler.assemble(scanLiterals); this.completeKeys.add(assembler); } else if (scanLiterals.supportPartialRowKeyScan(this.graph)) { PartialRowKeyScanAssembler assembler = new PartialRowKeyScanAssembler(this.rootType); assembler.assemble(scanLiterals); this.partialKeyScans.add(assembler); } else { FuzzyRowKeyScanAssembler assembler = new FuzzyRowKeyScanAssembler(this.rootType); assembler.assemble(scanLiterals); this.fuzzyKeyScans.add(assembler); } } } } public boolean isQueryRequiresGraphRecognizer() { return queryRequiresGraphRecognizer; } public List getPartialRowKeyScans() { init(); return this.partialKeyScans; } public List getFuzzyRowKeyScans() { init(); return this.fuzzyKeyScans; } public List getCompleteRowKeys() { init(); return this.completeKeys; } @Override public void visit(Expr target, Expr source, int level) { if (target instanceof RelationalBinaryExpr) { RelationalBinaryExpr expr = (RelationalBinaryExpr)target; collect(expr, source); } else if (target instanceof WildcardBinaryExpr) { WildcardBinaryExpr expr = (WildcardBinaryExpr)target; collect(expr, source); } } private void collect(RelationalBinaryExpr target, Expr source) { UserDefinedRowKeyFieldConfig fieldConfig = graph.getUserDefinedRowKeyField(target.getPropertyPath()); if (fieldConfig == null) { log.warn("no user defined row-key field for query path '" + target.getPropertyPath() + "' - deferring to graph recogniser post processor"); this.queryRequiresGraphRecognizer = true; return; } PlasmaProperty property = (PlasmaProperty)fieldConfig.getEndpointProperty(); ScanLiteral scanLiteral = factory.createLiteral( target.getLiteral().getValue(), property, (PlasmaType)graph.getRootType(), target.getOperator(), fieldConfig); if (log.isDebugEnabled()) log.debug("collecting path: " + target.getPropertyPath()); collect(scanLiteral, fieldConfig, source); } private void collect(WildcardBinaryExpr target, Expr source) { UserDefinedRowKeyFieldConfig fieldConfig = graph.getUserDefinedRowKeyField(target.getPropertyPath()); if (fieldConfig == null) { log.warn("no user defined row-key field for query path '" + target.getPropertyPath() + "' - deferring to graph recogniser post processor"); this.queryRequiresGraphRecognizer = true; return; } PlasmaProperty property = (PlasmaProperty)fieldConfig.getEndpointProperty(); ScanLiteral scanLiteral = factory.createLiteral( target.getLiteral().getValue(), property, (PlasmaType)graph.getRootType(), target.getOperator(), fieldConfig); if (log.isDebugEnabled()) log.debug("collecting path: " + target.getPropertyPath()); collect(scanLiteral, fieldConfig, source); } private void collect(ScanLiteral scanLiteral, UserDefinedRowKeyFieldConfig fieldConfig, Expr source) { if (source != null) { if (source instanceof LogicalBinaryExpr) { LogicalBinaryExpr lbe = (LogicalBinaryExpr)source; this.collect(fieldConfig, lbe, scanLiteral); } else throw new IllegalOperatorMappingException("expected logical binary expression parent not, " + source.getClass().getName()); } else { this.collect(fieldConfig, null, scanLiteral); } } private void collect (UserDefinedRowKeyFieldConfig fieldConfig, LogicalBinaryExpr source, ScanLiteral scanLiteral) { if (this.literals.size() == 0) { Map> map = new HashMap>(); List list = new ArrayList(2); list.add(scanLiteral); map.put(fieldConfig, list); this.literals.add(map); } else if (this.literals.size() > 0) { boolean foundField = false; for (Map> existingMap : literals) { if (source == null || source.getOperator().getValue().ordinal() == LogicalOperatorValues.AND.ordinal()) { List list = existingMap.get(fieldConfig); if (list == null) { list = new ArrayList(); list.add(scanLiteral); existingMap.put(fieldConfig, list); } else if (list.size() == 1) { ScanLiteral existingLiteral = list.get(0); //FIXME: 2 and-ed wildcard expressions cause a NPE here as there is no relational operator in a WC RelationalOperatorValues existingOperator = existingLiteral.getRelationalOperator().getValue(); switch (scanLiteral.getRelationalOperator().getValue()) { case GREATER_THAN: case GREATER_THAN_EQUALS: if (existingOperator.ordinal() != RelationalOperatorValues.LESS_THAN.ordinal() && existingOperator.ordinal() != RelationalOperatorValues.LESS_THAN_EQUALS.ordinal()) throw new ImbalancedOperatorMappingException( scanLiteral.getRelationalOperator().getValue(), LogicalOperatorValues.AND, existingOperator, fieldConfig); list.add(scanLiteral); break; case LESS_THAN: case LESS_THAN_EQUALS: if (existingOperator.ordinal() != RelationalOperatorValues.GREATER_THAN.ordinal() && existingOperator.ordinal() != RelationalOperatorValues.GREATER_THAN_EQUALS.ordinal()) throw new ImbalancedOperatorMappingException( scanLiteral.getRelationalOperator().getValue(), LogicalOperatorValues.AND, existingOperator, fieldConfig); list.add(scanLiteral); break; case EQUALS: case NOT_EQUALS: default: throw new IllegalOperatorMappingException("relational operator '" + scanLiteral.getRelationalOperator().getValue() + "' linked through logical operator '" + LogicalOperatorValues.AND + "to row key field property, " + fieldConfig.getEndpointProperty().getContainingType().toString() + "." + fieldConfig.getEndpointProperty().getName()); } } else { throw new IllegalOperatorMappingException("logical operator '" + LogicalOperatorValues.AND + "' mapped more than 2 times " + "to row key field property, " + fieldConfig.getEndpointProperty().getContainingType().toString() + "." + fieldConfig.getEndpointProperty().getName()); } } else if (source.getOperator().getValue().ordinal() == LogicalOperatorValues.OR.ordinal()) { List list = existingMap.get(fieldConfig); if (list == null) { if (foundField) throw new IllegalStateException("expected for key field mapped to scans " + "for row key field property, " + fieldConfig.getEndpointProperty().getContainingType().toString() + "." + fieldConfig.getEndpointProperty().getName()); list = new ArrayList(); list.add(scanLiteral); existingMap.put(fieldConfig, list); } else { foundField = true; } } else { log.warn("unsuported logical operator, " + source.getOperator().getValue() + " - ignoring"); } } if (foundField) { // duplicate any map with new literal Map> next = newMap(literals.get(0), fieldConfig, scanLiteral); literals.add(next); } } } /** * Duplicates the given map except with the given literal * replacing the mapping for the given field configuration * @param existing the existing source map * @param fieldConfig the fiend configuration * @param scanLiteral the literal * @return the new map */ private Map> newMap( Map> existing, UserDefinedRowKeyFieldConfig fieldConfig, ScanLiteral scanLiteral) { Map> next = new HashMap>(); for (UserDefinedRowKeyFieldConfig config : existing.keySet()) { if (!config.equals(fieldConfig)) { next.put(config, existing.get(config)); } else { List list = new ArrayList(2); list.add(scanLiteral); next.put(fieldConfig, list); } } return next; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy