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))));
}
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());
}
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");
}
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);
}
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;
}
Aggregations