Search in sources :

Example 1 with MapTableIndex

use of com.hazelcast.sql.impl.schema.map.MapTableIndex in project hazelcast by hazelcast.

the class IMapSqlConnector method createTable.

@Nonnull
@Override
public Table createTable(@Nonnull NodeEngine nodeEngine, @Nonnull String schemaName, @Nonnull String mappingName, @Nonnull String externalName, @Nonnull Map<String, String> options, @Nonnull List<MappingField> resolvedFields) {
    InternalSerializationService ss = (InternalSerializationService) nodeEngine.getSerializationService();
    KvMetadata keyMetadata = METADATA_RESOLVERS.resolveMetadata(true, resolvedFields, options, ss);
    KvMetadata valueMetadata = METADATA_RESOLVERS.resolveMetadata(false, resolvedFields, options, ss);
    List<TableField> fields = concat(keyMetadata.getFields().stream(), valueMetadata.getFields().stream()).collect(toList());
    MapService service = nodeEngine.getService(MapService.SERVICE_NAME);
    MapServiceContext context = service.getMapServiceContext();
    MapContainer container = context.getExistingMapContainer(externalName);
    long estimatedRowCount = estimatePartitionedMapRowCount(nodeEngine, context, externalName);
    boolean hd = container != null && container.getMapConfig().getInMemoryFormat() == InMemoryFormat.NATIVE;
    List<MapTableIndex> indexes = container != null ? MapTableUtils.getPartitionedMapIndexes(container, fields) : emptyList();
    return new PartitionedMapTable(schemaName, mappingName, externalName, fields, new ConstantTableStatistics(estimatedRowCount), keyMetadata.getQueryTargetDescriptor(), valueMetadata.getQueryTargetDescriptor(), keyMetadata.getUpsertTargetDescriptor(), valueMetadata.getUpsertTargetDescriptor(), indexes, hd);
}
Also used : TableField(com.hazelcast.sql.impl.schema.TableField) KvMetadata(com.hazelcast.jet.sql.impl.connector.keyvalue.KvMetadata) ConstantTableStatistics(com.hazelcast.sql.impl.schema.ConstantTableStatistics) MapServiceContext(com.hazelcast.map.impl.MapServiceContext) MapContainer(com.hazelcast.map.impl.MapContainer) MapTableIndex(com.hazelcast.sql.impl.schema.map.MapTableIndex) PartitionedMapTable(com.hazelcast.sql.impl.schema.map.PartitionedMapTable) InternalSerializationService(com.hazelcast.internal.serialization.InternalSerializationService) MapService(com.hazelcast.map.impl.MapService) Nonnull(javax.annotation.Nonnull)

Example 2 with MapTableIndex

use of com.hazelcast.sql.impl.schema.map.MapTableIndex in project hazelcast by hazelcast.

the class IndexResolver method buildCollationTrait.

/**
 * Builds a collation with collation fields re-mapped according to the table projections.
 *
 * @param scan  the logical map scan
 * @param index the index
 * @param ascs  the collation of index fields
 * @return the new collation trait
 */
private static RelCollation buildCollationTrait(FullScanLogicalRel scan, MapTableIndex index, List<Boolean> ascs) {
    if (index.getType() != SORTED) {
        return RelCollations.of(Collections.emptyList());
    }
    List<RelFieldCollation> fields = new ArrayList<>(index.getFieldOrdinals().size());
    HazelcastTable table = OptUtils.extractHazelcastTable(scan);
    // Extract those projections that are direct input field references. Only those can be used
    // for index access
    List<Integer> fieldProjects = table.getProjects().stream().filter(expr -> expr instanceof RexInputRef).map(inputRef -> ((RexInputRef) inputRef).getIndex()).collect(Collectors.toList());
    for (int i = 0; i < index.getFieldOrdinals().size(); ++i) {
        Integer indexFieldOrdinal = index.getFieldOrdinals().get(i);
        int remappedIndexFieldOrdinal = fieldProjects.indexOf(indexFieldOrdinal);
        if (remappedIndexFieldOrdinal == -1) {
            // The field is not used in the query
            break;
        }
        Direction direction = ascs.get(i) ? ASCENDING : DESCENDING;
        RelFieldCollation fieldCollation = new RelFieldCollation(remappedIndexFieldOrdinal, direction);
        fields.add(fieldCollation);
    }
    return RelCollations.of(fields);
}
Also used : RangeSet(com.google.common.collect.RangeSet) QueryDataTypeFamily(com.hazelcast.sql.impl.type.QueryDataTypeFamily) OptUtils.getCluster(com.hazelcast.jet.sql.impl.opt.OptUtils.getCluster) QueryParameterMetadata(com.hazelcast.sql.impl.QueryParameterMetadata) Collections.singletonList(java.util.Collections.singletonList) HazelcastTable(com.hazelcast.jet.sql.impl.schema.HazelcastTable) TypeConverters(com.hazelcast.query.impl.TypeConverters) RexUtil(org.apache.calcite.rex.RexUtil) RexNode(org.apache.calcite.rex.RexNode) Map(java.util.Map) IndexRangeFilter(com.hazelcast.sql.impl.exec.scan.index.IndexRangeFilter) QueryDataTypeUtils(com.hazelcast.sql.impl.type.QueryDataTypeUtils) HASH(com.hazelcast.config.IndexType.HASH) IndexEqualsFilter(com.hazelcast.sql.impl.exec.scan.index.IndexEqualsFilter) RexToExpressionVisitor(com.hazelcast.jet.sql.impl.opt.physical.visitor.RexToExpressionVisitor) PlanNodeFieldTypeProvider(com.hazelcast.sql.impl.plan.node.PlanNodeFieldTypeProvider) RelTraitSet(org.apache.calcite.plan.RelTraitSet) SqlKind(org.apache.calcite.sql.SqlKind) HazelcastTypeUtils(com.hazelcast.jet.sql.impl.validate.types.HazelcastTypeUtils) RexLiteral(org.apache.calcite.rex.RexLiteral) Collection(java.util.Collection) Range(com.google.common.collect.Range) Set(java.util.Set) RelFieldCollation(org.apache.calcite.rel.RelFieldCollation) Collectors(java.util.stream.Collectors) IndexInFilter(com.hazelcast.sql.impl.exec.scan.index.IndexInFilter) RexInputRef(org.apache.calcite.rex.RexInputRef) List(java.util.List) FullScanLogicalRel(com.hazelcast.jet.sql.impl.opt.logical.FullScanLogicalRel) BoundType(com.google.common.collect.BoundType) RelCollation(org.apache.calcite.rel.RelCollation) MapTableIndex(com.hazelcast.sql.impl.schema.map.MapTableIndex) TRUE(java.lang.Boolean.TRUE) RexCall(org.apache.calcite.rex.RexCall) OptUtils.createRelTable(com.hazelcast.jet.sql.impl.opt.OptUtils.createRelTable) Iterables(com.google.common.collect.Iterables) IndexFilterValue(com.hazelcast.sql.impl.exec.scan.index.IndexFilterValue) IndexFilter(com.hazelcast.sql.impl.exec.scan.index.IndexFilter) QueryDataType(com.hazelcast.sql.impl.type.QueryDataType) HashMap(java.util.HashMap) POSITIVE_INFINITY(com.hazelcast.query.impl.CompositeValue.POSITIVE_INFINITY) RelOptUtil(org.apache.calcite.plan.RelOptUtil) RelOptTable(org.apache.calcite.plan.RelOptTable) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) IndexType(com.hazelcast.config.IndexType) BiTuple(com.hazelcast.internal.util.BiTuple) Expression(com.hazelcast.sql.impl.expression.Expression) Nonnull(javax.annotation.Nonnull) ComparableIdentifiedDataSerializable(com.hazelcast.query.impl.ComparableIdentifiedDataSerializable) RelCollations(org.apache.calcite.rel.RelCollations) RexToExpression(com.hazelcast.jet.sql.impl.opt.physical.visitor.RexToExpression) RelDataType(org.apache.calcite.rel.type.RelDataType) FALSE(java.lang.Boolean.FALSE) HazelcastRelOptTable(com.hazelcast.jet.sql.impl.schema.HazelcastRelOptTable) RelCollationTraitDef(org.apache.calcite.rel.RelCollationTraitDef) SqlTypeName(org.apache.calcite.sql.type.SqlTypeName) SORTED(com.hazelcast.config.IndexType.SORTED) Util.toList(com.hazelcast.jet.impl.util.Util.toList) RexBuilder(org.apache.calcite.rex.RexBuilder) OptUtils(com.hazelcast.jet.sql.impl.opt.OptUtils) IndexScanMapPhysicalRel(com.hazelcast.jet.sql.impl.opt.physical.IndexScanMapPhysicalRel) RelNode(org.apache.calcite.rel.RelNode) Direction(org.apache.calcite.rel.RelFieldCollation.Direction) ASCENDING(org.apache.calcite.rel.RelFieldCollation.Direction.ASCENDING) TreeMap(java.util.TreeMap) NEGATIVE_INFINITY(com.hazelcast.query.impl.CompositeValue.NEGATIVE_INFINITY) ConstantExpression(com.hazelcast.sql.impl.expression.ConstantExpression) DESCENDING(org.apache.calcite.rel.RelFieldCollation.Direction.DESCENDING) Collections(java.util.Collections) RelFieldCollation(org.apache.calcite.rel.RelFieldCollation) ArrayList(java.util.ArrayList) RexInputRef(org.apache.calcite.rex.RexInputRef) HazelcastTable(com.hazelcast.jet.sql.impl.schema.HazelcastTable) Direction(org.apache.calcite.rel.RelFieldCollation.Direction)

Example 3 with MapTableIndex

use of com.hazelcast.sql.impl.schema.map.MapTableIndex in project hazelcast by hazelcast.

the class SqlIndexResolutionTest method checkIndex.

private void checkIndex(IMap<?, ?> map, List<QueryDataType> expectedFieldConverterTypes) {
    String mapName = map.getName();
    List<PartitionedMapTable> tables = resolver.getTables().stream().filter(t -> t instanceof PartitionedMapTable).map(t -> (PartitionedMapTable) t).filter(t -> t.getMapName().equals(mapName)).collect(Collectors.toList());
    assertEquals(1, tables.size());
    PartitionedMapTable table = tables.get(0);
    assertEquals(1, table.getIndexes().size());
    MapTableIndex index = table.getIndexes().get(0);
    assertEquals(indexName, index.getName());
    assertEquals(indexType, index.getType());
    // Components count depends on the index attribute count
    assertEquals(composite ? 2 : 1, index.getComponentsCount());
    int field1Ordinal = findFieldOrdinal(table, "field1");
    int field2Ordinal = findFieldOrdinal(table, "field2");
    // Check resolved field converter types. We do not test more than two components.
    assertTrue(expectedFieldConverterTypes.size() <= 2);
    assertEquals(expectedFieldConverterTypes, index.getFieldConverterTypes());
    // Resolved field ordinals depend on the number of resolved converter types
    if (expectedFieldConverterTypes.isEmpty()) {
        assertTrue(index.getFieldOrdinals().isEmpty());
    } else if (expectedFieldConverterTypes.size() == 1) {
        assertEquals(singletonList(field1Ordinal), index.getFieldOrdinals());
    } else {
        assertEquals(Arrays.asList(field1Ordinal, field2Ordinal), index.getFieldOrdinals());
    }
}
Also used : ParallelJVMTest(com.hazelcast.test.annotation.ParallelJVMTest) Arrays(java.util.Arrays) BeforeClass(org.junit.BeforeClass) QuickTest(com.hazelcast.test.annotation.QuickTest) SqlStatement(com.hazelcast.sql.SqlStatement) QueryDataType(com.hazelcast.sql.impl.type.QueryDataType) RunWith(org.junit.runner.RunWith) ExpressionBiValue(com.hazelcast.jet.sql.impl.support.expressions.ExpressionBiValue) SqlConnectorCache(com.hazelcast.jet.sql.impl.connector.SqlConnectorCache) ArrayList(java.util.ArrayList) Collections.singletonList(java.util.Collections.singletonList) HazelcastTable(com.hazelcast.jet.sql.impl.schema.HazelcastTable) ExpressionBiValue.createBiValue(com.hazelcast.jet.sql.impl.support.expressions.ExpressionBiValue.createBiValue) IndexType(com.hazelcast.config.IndexType) OptimizerTestSupport(com.hazelcast.jet.sql.impl.opt.OptimizerTestSupport) Arrays.asList(java.util.Arrays.asList) QueryPath(com.hazelcast.sql.impl.extract.QueryPath) Assert.fail(org.junit.Assert.fail) PartitionedMapTable(com.hazelcast.sql.impl.schema.map.PartitionedMapTable) Parameterized(org.junit.runners.Parameterized) Before(org.junit.Before) UseParametersRunnerFactory(org.junit.runners.Parameterized.UseParametersRunnerFactory) NodeEngine(com.hazelcast.spi.impl.NodeEngine) HazelcastParametrizedRunner(com.hazelcast.test.HazelcastParametrizedRunner) Assert.assertNotNull(org.junit.Assert.assertNotNull) Collection(java.util.Collection) TableResolverImpl(com.hazelcast.jet.sql.impl.schema.TableResolverImpl) MapTableUtils.getPartitionedMapIndexes(com.hazelcast.sql.impl.schema.map.MapTableUtils.getPartitionedMapIndexes) Assert.assertTrue(org.junit.Assert.assertTrue) HazelcastParallelParametersRunnerFactory(com.hazelcast.test.HazelcastParallelParametersRunnerFactory) Test(org.junit.Test) ExpressionBiValue.createBiClass(com.hazelcast.jet.sql.impl.support.expressions.ExpressionBiValue.createBiClass) IndexScanMapPhysicalRel(com.hazelcast.jet.sql.impl.opt.physical.IndexScanMapPhysicalRel) Category(org.junit.experimental.categories.Category) FullScanPhysicalRel(com.hazelcast.jet.sql.impl.opt.physical.FullScanPhysicalRel) Collectors(java.util.stream.Collectors) TableField(com.hazelcast.sql.impl.schema.TableField) TableResolver(com.hazelcast.sql.impl.schema.TableResolver) List(java.util.List) Assert.assertNull(org.junit.Assert.assertNull) Util.getNodeEngine(com.hazelcast.jet.impl.util.Util.getNodeEngine) FullScanLogicalRel(com.hazelcast.jet.sql.impl.opt.logical.FullScanLogicalRel) MapTableField(com.hazelcast.sql.impl.schema.map.MapTableField) MapTableIndex(com.hazelcast.sql.impl.schema.map.MapTableIndex) ExpressionType(com.hazelcast.jet.sql.impl.support.expressions.ExpressionType) TablesStorage(com.hazelcast.jet.sql.impl.schema.TablesStorage) Assert.assertEquals(org.junit.Assert.assertEquals) IMap(com.hazelcast.map.IMap) MapTableIndex(com.hazelcast.sql.impl.schema.map.MapTableIndex) PartitionedMapTable(com.hazelcast.sql.impl.schema.map.PartitionedMapTable)

Example 4 with MapTableIndex

use of com.hazelcast.sql.impl.schema.map.MapTableIndex in project hazelcast by hazelcast.

the class IndexResolver method createIndexScans.

/**
 * The main entry point for index planning.
 * <p>
 * Analyzes the filter of the input scan operator, and produces zero, one or more {@link IndexScanMapPhysicalRel}
 * operators.
 * <p>
 * First, the full index scans are created and the covered (prefix-based) scans are excluded.
 * Second, the lookups are created and if lookup's collation is equal to the full scan's collation,
 * the latter one is excluded.
 *
 * @param scan    scan operator to be analyzed
 * @param indexes indexes available on the map being scanned
 * @return zero, one or more index scan rels
 */
@SuppressWarnings({ "checkstyle:CyclomaticComplexity", "checkstyle:NPathComplexity", "checkstyle:MethodLength" })
public static Collection<RelNode> createIndexScans(FullScanLogicalRel scan, List<MapTableIndex> indexes) {
    RexNode filter = OptUtils.extractHazelcastTable(scan).getFilter();
    // Filter out unsupported indexes. Only SORTED and HASH indexes are supported.
    List<MapTableIndex> supportedIndexes = new ArrayList<>(indexes.size());
    Set<Integer> allIndexedFieldOrdinals = new HashSet<>();
    for (MapTableIndex index : indexes) {
        if (isIndexSupported(index)) {
            supportedIndexes.add(index);
            allIndexedFieldOrdinals.addAll(index.getFieldOrdinals());
        }
    }
    // Early return if there are no indexes to consider.
    if (supportedIndexes.isEmpty()) {
        return Collections.emptyList();
    }
    List<RelNode> fullScanRels = new ArrayList<>(supportedIndexes.size());
    // possible ORDER BY clause on the upper level
    for (MapTableIndex index : supportedIndexes) {
        if (index.getType() == SORTED) {
            // Only for SORTED index create full index scans that might be potentially
            // utilized by sorting operator.
            List<Boolean> ascs = buildFieldDirections(index, true);
            RelNode relAscending = createFullIndexScan(scan, index, ascs, true);
            if (relAscending != null) {
                fullScanRels.add(relAscending);
                RelNode relDescending = replaceCollationDirection(relAscending, DESCENDING);
                fullScanRels.add(relDescending);
            }
        }
    }
    Map<RelCollation, RelNode> fullScanRelsMap = excludeCoveredCollations(fullScanRels);
    if (filter == null) {
        // Exclude prefix-based covered index scans
        return fullScanRelsMap.values();
    }
    // Convert expression into CNF. Examples:
    // - {a=1 AND b=2} is converted into {a=1}, {b=2}
    // - {a=1 OR b=2} is unchanged
    List<RexNode> conjunctions = createConjunctiveFilter(filter);
    // Create a map from a column to a list of expressions that could be used by indexes.
    // For example, for the expression {a>1 AND a<3 AND b=5 AND c>d}, three candidates will be created:
    // a -> {>1}, {<3}
    // b -> {=5}
    Map<Integer, List<IndexComponentCandidate>> candidates = prepareSingleColumnCandidates(conjunctions, getCluster(scan).getParameterMetadata(), allIndexedFieldOrdinals);
    if (candidates.isEmpty()) {
        return fullScanRelsMap.values();
    }
    List<RelNode> rels = new ArrayList<>(supportedIndexes.size());
    for (MapTableIndex index : supportedIndexes) {
        // Create index scan based on candidates, if possible. Candidates could be merged into more complex
        // filters whenever possible.
        List<Boolean> ascs = buildFieldDirections(index, true);
        RelNode relAscending = createIndexScan(scan, index, conjunctions, candidates, ascs);
        if (relAscending != null) {
            RelCollation relAscCollation = getCollation(relAscending);
            // Exclude a full scan that has the same collation
            fullScanRelsMap.remove(relAscCollation);
            rels.add(relAscending);
            if (relAscCollation.getFieldCollations().size() > 0) {
                RelNode relDescending = replaceCollationDirection(relAscending, DESCENDING);
                rels.add(relDescending);
                RelCollation relDescCollation = getCollation(relDescending);
                // Exclude a full scan that has the same collation
                fullScanRelsMap.remove(relDescCollation);
            }
        }
    }
    rels.addAll(fullScanRelsMap.values());
    return rels;
}
Also used : ArrayList(java.util.ArrayList) RelCollation(org.apache.calcite.rel.RelCollation) MapTableIndex(com.hazelcast.sql.impl.schema.map.MapTableIndex) RelNode(org.apache.calcite.rel.RelNode) Collections.singletonList(java.util.Collections.singletonList) List(java.util.List) ArrayList(java.util.ArrayList) Util.toList(com.hazelcast.jet.impl.util.Util.toList) RexNode(org.apache.calcite.rex.RexNode) HashSet(java.util.HashSet)

Aggregations

MapTableIndex (com.hazelcast.sql.impl.schema.map.MapTableIndex)4 IndexType (com.hazelcast.config.IndexType)2 Util.toList (com.hazelcast.jet.impl.util.Util.toList)2 FullScanLogicalRel (com.hazelcast.jet.sql.impl.opt.logical.FullScanLogicalRel)2 IndexScanMapPhysicalRel (com.hazelcast.jet.sql.impl.opt.physical.IndexScanMapPhysicalRel)2 HazelcastTable (com.hazelcast.jet.sql.impl.schema.HazelcastTable)2 ArrayList (java.util.ArrayList)2 Collections.singletonList (java.util.Collections.singletonList)2 List (java.util.List)2 Nonnull (javax.annotation.Nonnull)2 BoundType (com.google.common.collect.BoundType)1 Iterables (com.google.common.collect.Iterables)1 Range (com.google.common.collect.Range)1 RangeSet (com.google.common.collect.RangeSet)1 HASH (com.hazelcast.config.IndexType.HASH)1 SORTED (com.hazelcast.config.IndexType.SORTED)1 InternalSerializationService (com.hazelcast.internal.serialization.InternalSerializationService)1 BiTuple (com.hazelcast.internal.util.BiTuple)1 Util.getNodeEngine (com.hazelcast.jet.impl.util.Util.getNodeEngine)1 SqlConnectorCache (com.hazelcast.jet.sql.impl.connector.SqlConnectorCache)1