Search in sources :

Example 1 with NestingKeyExpression

use of com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression in project fdb-record-layer by FoundationDB.

the class ScalarTranslationVisitor method visitExpression.

@Nonnull
@Override
public Value visitExpression(@Nonnull final NestingKeyExpression nestingKeyExpression) {
    final FieldKeyExpression parent = nestingKeyExpression.getParent();
    final KeyExpression.FanType fanType = parent.getFanType();
    if (fanType != KeyExpression.FanType.None) {
        throw new RecordCoreException("cannot expand fan outs in scalar expansion");
    }
    final ScalarVisitorState state = getCurrentState();
    final List<String> fieldNamePrefix = state.getFieldNamePrefix();
    final KeyExpression child = nestingKeyExpression.getChild();
    final List<String> newPrefix = ImmutableList.<String>builder().addAll(fieldNamePrefix).add(parent.getFieldName()).build();
    return pop(child.expand(push(state.withFieldNamePrefix(newPrefix))));
}
Also used : RecordCoreException(com.apple.foundationdb.record.RecordCoreException) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) NestingKeyExpression(com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression) ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) EmptyKeyExpression(com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression) Nonnull(javax.annotation.Nonnull)

Example 2 with NestingKeyExpression

use of com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression in project fdb-record-layer by FoundationDB.

the class KeyExpressionTest method testSerializeNesting.

@Test
public void testSerializeNesting() throws Exception {
    final NestingKeyExpression nest = field("f1").nest(field("f2", FanType.FanOut).nest("f3"));
    final NestingKeyExpression reserialized = new NestingKeyExpression(nest.toProto());
    assertEquals("f1", reserialized.getParent().getFieldName());
    final NestingKeyExpression child = (NestingKeyExpression) reserialized.getChild();
    assertEquals("f2", child.getParent().getFieldName());
    assertEquals(FanType.FanOut, child.getParent().getFanType());
}
Also used : NestingKeyExpression(com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression) Test(org.junit.jupiter.api.Test) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Example 3 with NestingKeyExpression

use of com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression in project fdb-record-layer by FoundationDB.

the class LuceneIndexExpressions method getFieldsRecursively.

@SuppressWarnings("squid:S3776")
public static <T extends RecordSource<T>> void getFieldsRecursively(@Nonnull KeyExpression expression, @Nonnull T source, @Nonnull DocumentDestination<T> destination, @Nullable String fieldNamePrefix, int keyIndex, int groupingCount, @Nonnull List<Integer> overriddenKeyRanges) {
    if (expression instanceof ThenKeyExpression) {
        int count = 0;
        for (KeyExpression child : ((ThenKeyExpression) expression).getChildren()) {
            getFieldsRecursively(child, source, destination, fieldNamePrefix, keyIndex + count, groupingCount, overriddenKeyRanges);
            count += child.getColumnSize();
        }
        return;
    }
    String fieldNameSuffix = null;
    boolean suffixOverride = false;
    if (expression instanceof LuceneFunctionKeyExpression.LuceneFieldName) {
        LuceneFunctionKeyExpression.LuceneFieldName fieldNameExpression = (LuceneFunctionKeyExpression.LuceneFieldName) expression;
        KeyExpression nameExpression = fieldNameExpression.getNameExpression();
        if (nameExpression instanceof LiteralKeyExpression) {
            fieldNameSuffix = (String) ((LiteralKeyExpression<?>) nameExpression).getValue();
        } else if (nameExpression instanceof FieldKeyExpression) {
            Iterator<Object> names = source.getValues((FieldKeyExpression) nameExpression).iterator();
            if (names.hasNext()) {
                fieldNameSuffix = (String) names.next();
                if (names.hasNext()) {
                    throw new RecordCoreException("Lucene field name override should evaluate to single value");
                }
            }
        } else {
            throw new RecordCoreException("Lucene field name override should be a literal or a field");
        }
        suffixOverride = true;
        expression = fieldNameExpression.getNamedExpression();
    }
    if (expression instanceof NestingKeyExpression) {
        NestingKeyExpression nestingExpression = (NestingKeyExpression) expression;
        FieldKeyExpression parentExpression = nestingExpression.getParent();
        KeyExpression child = nestingExpression.getChild();
        if (!suffixOverride) {
            fieldNameSuffix = parentExpression.getFieldName();
        } else {
            addOverriddenKeyRange(overriddenKeyRanges, fieldNamePrefix, fieldNameSuffix);
        }
        String fieldName = appendFieldName(fieldNamePrefix, fieldNameSuffix);
        for (T subsource : source.getChildren(parentExpression)) {
            getFieldsRecursively(child, subsource, destination, fieldName, keyIndex, groupingCount, overriddenKeyRanges);
        }
        if (suffixOverride) {
            // Remove the last 2 numbers added above
            removedLastOverriddenKeyRange(overriddenKeyRanges);
        }
        return;
    }
    boolean fieldStored = false;
    boolean fieldText = false;
    while (true) {
        if (expression instanceof LuceneFunctionKeyExpression.LuceneStored) {
            LuceneFunctionKeyExpression.LuceneStored storedExpression = (LuceneFunctionKeyExpression.LuceneStored) expression;
            fieldStored = true;
            expression = storedExpression.getStoredExpression();
        } else if (expression instanceof LuceneFunctionKeyExpression.LuceneText) {
            LuceneFunctionKeyExpression.LuceneText textExpression = (LuceneFunctionKeyExpression.LuceneText) expression;
            fieldText = true;
            expression = textExpression.getFieldExpression();
        } else {
            // TODO: More text options.
            break;
        }
    }
    if (expression instanceof FieldKeyExpression) {
        FieldKeyExpression fieldExpression = (FieldKeyExpression) expression;
        if (!suffixOverride) {
            fieldNameSuffix = fieldExpression.getFieldName();
        } else {
            addOverriddenKeyRange(overriddenKeyRanges, fieldNamePrefix, fieldNameSuffix);
        }
        String fieldName = appendFieldName(fieldNamePrefix, fieldNameSuffix);
        if (fieldName == null) {
            fieldName = "_";
        }
        Descriptors.Descriptor recordDescriptor = source.getDescriptor();
        Descriptors.FieldDescriptor fieldDescriptor = recordDescriptor.findFieldByName(fieldExpression.getFieldName());
        DocumentFieldType fieldType;
        if (fieldText) {
            switch(fieldDescriptor.getJavaType()) {
                case STRING:
                    fieldType = DocumentFieldType.TEXT;
                    break;
                default:
                    throw new RecordCoreException("Unknown Lucene text field type");
            }
        } else {
            switch(fieldDescriptor.getJavaType()) {
                case STRING:
                    fieldType = DocumentFieldType.STRING;
                    break;
                case INT:
                    fieldType = DocumentFieldType.INT;
                    break;
                case LONG:
                    fieldType = DocumentFieldType.LONG;
                    break;
                case DOUBLE:
                    fieldType = DocumentFieldType.DOUBLE;
                    break;
                case BOOLEAN:
                    fieldType = DocumentFieldType.BOOLEAN;
                    break;
                default:
                    throw new RecordCoreException("Unknown Lucene field type");
            }
        }
        for (Object value : source.getValues(fieldExpression)) {
            destination.addField(source, fieldName, value, fieldType, fieldStored, overriddenKeyRanges, keyIndex < groupingCount ? keyIndex : -1);
        }
        if (suffixOverride) {
            // Remove the last 2 numbers added above
            removedLastOverriddenKeyRange(overriddenKeyRanges);
        }
        return;
    }
    throw new RecordCoreException("Unknown Lucene field key expression");
}
Also used : ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) LiteralKeyExpression(com.apple.foundationdb.record.metadata.expressions.LiteralKeyExpression) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) NestingKeyExpression(com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) NestingKeyExpression(com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression) Iterator(java.util.Iterator) Descriptors(com.google.protobuf.Descriptors) LiteralKeyExpression(com.apple.foundationdb.record.metadata.expressions.LiteralKeyExpression)

Example 4 with NestingKeyExpression

use of com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression in project fdb-record-layer by FoundationDB.

the class LuceneDocumentFromRecord method getGroupedFields.

// Grouping keys are evaluated more or less normally, turning into multiple groups.
// Each group corresponds to a single document in a separate index / directory.
// Within that document, the grouped fields are merged.
protected static <M extends Message> void getGroupedFields(@Nonnull List<KeyExpression> keys, int keyIndex, int keyPosition, int groupingCount, @Nonnull Tuple groupPrefix, @Nonnull FDBRecord<M> rec, @Nonnull Message message, @Nonnull Map<Tuple, List<DocumentField>> result, @Nullable String fieldNamePrefix) {
    if (keyIndex >= keys.size()) {
        return;
    }
    KeyExpression key = keys.get(keyIndex);
    int keySize = key.getColumnSize();
    if (keyPosition + keySize <= groupingCount) {
        // Entirely in the grouping portion: extend group prefix with normal evaluation.
        List<Key.Evaluated> groups = key.evaluateMessage(rec, message);
        for (Key.Evaluated group : groups) {
            Tuple wholeGroup = groupPrefix.addAll(group.toTupleAppropriateList());
            if (groupingCount == wholeGroup.size()) {
                result.putIfAbsent(wholeGroup, new ArrayList<>());
            }
            getGroupedFields(keys, keyIndex + 1, keyPosition + key.getColumnSize(), groupingCount, wholeGroup, rec, message, result, fieldNamePrefix);
        }
        return;
    }
    if (groupingCount <= keyPosition) {
        // Entirely in the grouped portion: add fields to groups.
        List<DocumentField> fields = getFields(key, rec, message, fieldNamePrefix);
        for (Map.Entry<Tuple, List<DocumentField>> entry : result.entrySet()) {
            if (TupleHelpers.isPrefix(groupPrefix, entry.getKey())) {
                entry.getValue().addAll(fields);
            }
        }
    // Grouping ends in the middle of this key: break it apart.
    } else if (key instanceof NestingKeyExpression) {
        NestingKeyExpression nesting = (NestingKeyExpression) key;
        final String parentFieldName = nesting.getParent().getFieldName();
        for (Key.Evaluated value : nesting.getParent().evaluateMessage(rec, message)) {
            final Message submessage = (Message) value.toList().get(0);
            getGroupedFields(Collections.singletonList(nesting.getChild()), 0, keyPosition, groupingCount, groupPrefix, rec, submessage, result, fieldNamePrefix == null ? parentFieldName : fieldNamePrefix + "_" + parentFieldName);
        }
    } else if (key instanceof ThenKeyExpression) {
        ThenKeyExpression then = (ThenKeyExpression) key;
        getGroupedFields(then.getChildren(), 0, keyPosition, groupingCount, groupPrefix, rec, message, result, fieldNamePrefix);
    } else {
        throw new RecordCoreException("Cannot split key for document grouping: " + key);
    }
    // Continue with remaining keys.
    getGroupedFields(keys, keyIndex + 1, keyPosition + key.getColumnSize(), groupingCount, groupPrefix, rec, message, result, fieldNamePrefix);
}
Also used : ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) Message(com.google.protobuf.Message) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) NestingKeyExpression(com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) NestingKeyExpression(com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) Key(com.apple.foundationdb.record.metadata.Key) Tuple(com.apple.foundationdb.tuple.Tuple)

Example 5 with NestingKeyExpression

use of com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression in project fdb-record-layer by FoundationDB.

the class RecordQueryPlanner method planOneOfThemWithComparison.

@Nullable
private ScoredPlan planOneOfThemWithComparison(@Nonnull CandidateScan candidateScan, @Nonnull KeyExpression indexExpr, @Nonnull OneOfThemWithComparison oneOfThemWithComparison, @Nullable KeyExpression sort) {
    final Comparisons.Comparison comparison = oneOfThemWithComparison.getComparison();
    final ScanComparisons scanComparisons = ScanComparisons.from(comparison);
    if (scanComparisons == null) {
        final ScoredPlan sortOnlyPlan = planSortOnly(candidateScan, indexExpr, sort);
        if (sortOnlyPlan != null) {
            return new ScoredPlan(0, sortOnlyPlan.plan, Collections.<QueryComponent>singletonList(oneOfThemWithComparison), sortOnlyPlan.createsDuplicates);
        } else {
            return null;
        }
    }
    if (indexExpr instanceof FieldKeyExpression) {
        FieldKeyExpression field = (FieldKeyExpression) indexExpr;
        if (Objects.equals(oneOfThemWithComparison.getFieldName(), field.getFieldName()) && field.getFanType() == FanType.FanOut) {
            if (sort != null) {
                if (sort instanceof FieldKeyExpression) {
                    FieldKeyExpression sortField = (FieldKeyExpression) sort;
                    if (Objects.equals(sortField.getFieldName(), field.getFieldName())) {
                        // everything matches, yay!! Hopefully that comparison can be for tuples
                        return new ScoredPlan(1, valueScan(candidateScan, scanComparisons, true), Collections.<QueryComponent>emptyList(), true);
                    }
                }
            } else {
                return new ScoredPlan(1, valueScan(candidateScan, scanComparisons, false), Collections.<QueryComponent>emptyList(), true);
            }
        }
        return null;
    } else if (indexExpr instanceof ThenKeyExpression) {
        // May need second column to do sort, so handle like And, which does such cases.
        ThenKeyExpression then = (ThenKeyExpression) indexExpr;
        return new AndWithThenPlanner(candidateScan, then, Collections.singletonList(oneOfThemWithComparison), sort).plan();
    } else if (indexExpr instanceof NestingKeyExpression) {
        return null;
    }
    return null;
}
Also used : ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) TimeWindowScanComparisons(com.apple.foundationdb.record.provider.foundationdb.leaderboard.TimeWindowScanComparisons) IndexScanComparisons(com.apple.foundationdb.record.provider.foundationdb.IndexScanComparisons) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) NestingKeyExpression(com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression) TimeWindowScanComparisons(com.apple.foundationdb.record.provider.foundationdb.leaderboard.TimeWindowScanComparisons) IndexScanComparisons(com.apple.foundationdb.record.provider.foundationdb.IndexScanComparisons) RankComparisons(com.apple.foundationdb.record.query.plan.planning.RankComparisons) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) Nullable(javax.annotation.Nullable)

Aggregations

NestingKeyExpression (com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression)10 FieldKeyExpression (com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression)9 ThenKeyExpression (com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression)6 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)5 KeyExpression (com.apple.foundationdb.record.metadata.expressions.KeyExpression)5 GroupingKeyExpression (com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression)3 QueryComponent (com.apple.foundationdb.record.query.expressions.QueryComponent)3 Nonnull (javax.annotation.Nonnull)3 Nullable (javax.annotation.Nullable)3 EmptyKeyExpression (com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression)2 Comparisons (com.apple.foundationdb.record.query.expressions.Comparisons)2 FieldWithComparison (com.apple.foundationdb.record.query.expressions.FieldWithComparison)2 NestedField (com.apple.foundationdb.record.query.expressions.NestedField)2 Tuple (com.apple.foundationdb.tuple.Tuple)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 List (java.util.List)2 Map (java.util.Map)2 API (com.apple.foundationdb.annotation.API)1 Bindings (com.apple.foundationdb.record.Bindings)1