Search in sources :

Example 1 with IndexPostfix

use of com.google.storage.onestore.v3.OnestoreEntity.IndexPostfix in project appengine-java-standard by GoogleCloudPlatform.

the class CompositeIndexManager method minimumCompositeIndexForQuery.

/**
 * Given a {@link IndexComponentsOnlyQuery} and a collection of existing {@link Index}s, return
 * the minimum {@link Index} needed to fulfill the query, or {@code null} if no index is needed.
 *
 * <p>This code needs to remain in sync with its counterparts in other languages. If you modify
 * this code please make sure you make the same update in the local datastore for other languages.
 *
 * @param indexOnlyQuery The query.
 * @param indexes The existing indexes.
 * @return The minimum index that must be present in order to fulfill the query, or {@code null}
 *     if no index is needed.
 */
@Nullable
protected Index minimumCompositeIndexForQuery(IndexComponentsOnlyQuery indexOnlyQuery, Collection<Index> indexes) {
    Index suggestedIndex = compositeIndexForQuery(indexOnlyQuery);
    if (suggestedIndex == null) {
        return null;
    }
    if (indexOnlyQuery.isGeo()) {
        // None of the shortcuts/optimizations below are applicable for Search indexes.
        return suggestedIndex;
    }
    class EqPropsAndAncestorConstraint {

        final Set<String> equalityProperties;

        final boolean ancestorConstraint;

        EqPropsAndAncestorConstraint(Set<String> equalityProperties, boolean ancestorConstraint) {
            this.equalityProperties = equalityProperties;
            this.ancestorConstraint = ancestorConstraint;
        }
    }
    // Map from postfix to the remaining equality properties and ancestor constraints.
    Map<List<Property>, EqPropsAndAncestorConstraint> remainingMap = new HashMap<List<Property>, EqPropsAndAncestorConstraint>();
    index_for: for (Index index : indexes) {
        if (// Kind must match.
        !indexOnlyQuery.getQuery().getKind().equals(index.getEntityType()) || // Ancestor indexes can only be used on ancestor queries.
        (!indexOnlyQuery.getQuery().hasAncestor() && index.isAncestor())) {
            continue;
        }
        // Matching the postfix.
        int postfixSplit = index.propertySize();
        for (IndexComponent component : Lists.reverse(indexOnlyQuery.getPostfix())) {
            if (!component.matches(index.propertys().subList(Math.max(postfixSplit - component.size(), 0), postfixSplit))) {
                continue index_for;
            }
            postfixSplit -= component.size();
        }
        // Postfix matches! Now checking the prefix.
        Set<String> indexEqProps = Sets.newHashSetWithExpectedSize(postfixSplit);
        for (Property prop : index.propertys().subList(0, postfixSplit)) {
            // Index must not contain extra properties in the prefix.
            if (!indexOnlyQuery.getPrefix().contains(prop.getName())) {
                continue index_for;
            }
            indexEqProps.add(prop.getName());
        }
        // Index matches!
        // Find the matching remaining requirements.
        List<Property> indexPostfix = index.propertys().subList(postfixSplit, index.propertySize());
        Set<String> remainingEqProps;
        boolean remainingAncestor;
        {
            EqPropsAndAncestorConstraint remaining = remainingMap.get(indexPostfix);
            if (remaining == null) {
                remainingEqProps = Sets.newHashSet(indexOnlyQuery.getPrefix());
                remainingAncestor = indexOnlyQuery.getQuery().hasAncestor();
            } else {
                remainingEqProps = remaining.equalityProperties;
                remainingAncestor = remaining.ancestorConstraint;
            }
        }
        // Remove any remaining requirements handled by this index.
        boolean modified = remainingEqProps.removeAll(indexEqProps);
        if (remainingAncestor && index.isAncestor()) {
            modified = true;
            remainingAncestor = false;
        }
        if (remainingEqProps.isEmpty() && !remainingAncestor) {
            // No new index needed!
            return null;
        }
        if (!modified) {
            // Index made no contribution, don't update the map.
            continue;
        }
        // Save indexes contribution
        remainingMap.put(indexPostfix, new EqPropsAndAncestorConstraint(remainingEqProps, remainingAncestor));
    }
    if (remainingMap.isEmpty()) {
        // suggested index is the minimum index
        return suggestedIndex;
    }
    int minimumCost = Integer.MAX_VALUE;
    List<Property> minimumPostfix = null;
    EqPropsAndAncestorConstraint minimumRemaining = null;
    for (Map.Entry<List<Property>, EqPropsAndAncestorConstraint> entry : remainingMap.entrySet()) {
        int cost = entry.getValue().equalityProperties.size();
        if (entry.getValue().ancestorConstraint) {
            // Arbitrary value picked because ancestor are multi-valued.
            cost += 2;
        }
        if (cost < minimumCost) {
            minimumCost = cost;
            minimumPostfix = entry.getKey();
            minimumRemaining = entry.getValue();
        }
    }
    // map not empty so we should have found cost < MAX_VALUE.
    requireNonNull(minimumRemaining);
    requireNonNull(minimumPostfix);
    // Populating suggesting the minimal index instead.
    suggestedIndex.clearProperty();
    suggestedIndex.setAncestor(minimumRemaining.ancestorConstraint);
    for (String name : minimumRemaining.equalityProperties) {
        suggestedIndex.addProperty().setName(name).setDirection(Direction.ASCENDING);
    }
    Collections.sort(suggestedIndex.mutablePropertys(), PROPERTY_NAME_COMPARATOR);
    suggestedIndex.mutablePropertys().addAll(minimumPostfix);
    return suggestedIndex;
}
Also used : Set(java.util.Set) HashMap(java.util.HashMap) Index(com.google.storage.onestore.v3.OnestoreEntity.Index) ArrayList(java.util.ArrayList) List(java.util.List) Property(com.google.storage.onestore.v3.OnestoreEntity.Index.Property) HashMap(java.util.HashMap) Map(java.util.Map) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Example 2 with IndexPostfix

use of com.google.storage.onestore.v3.OnestoreEntity.IndexPostfix in project appengine-java-standard by GoogleCloudPlatform.

the class CursorTest method testReverseCursorPostfix.

@SuppressWarnings("deprecation")
@Test
public void testReverseCursorPostfix() {
    IndexPostfix postfixPosition = new IndexPostfix().setKey(new Reference()).setBefore(true);
    Cursor pfCursor = toCursor(new CompiledCursor().setPostfixPosition(postfixPosition));
    // reverse() is a no-op.
    Cursor pfReverse = pfCursor.reverse();
    assertThat(pfReverse).isEqualTo(pfCursor);
    assertThat(pfCursor).isEqualTo(pfReverse.reverse());
}
Also used : IndexPostfix(com.google.storage.onestore.v3.OnestoreEntity.IndexPostfix) Reference(com.google.storage.onestore.v3.OnestoreEntity.Reference) CompiledCursor(com.google.apphosting.datastore.DatastoreV3Pb.CompiledCursor) CompiledCursor(com.google.apphosting.datastore.DatastoreV3Pb.CompiledCursor) Test(org.junit.Test)

Example 3 with IndexPostfix

use of com.google.storage.onestore.v3.OnestoreEntity.IndexPostfix in project appengine-java-standard by GoogleCloudPlatform.

the class CursorModernizer method modernizeCursor.

public static void modernizeCursor(CompiledCursor cursor, @Nullable DatastoreV3Pb.Query.Order.Direction firstSortDirection) throws InvalidConversionException {
    // First, convert any contents of the position field.
    if (cursor.hasPosition()) {
        InvalidConversionException.checkConversion(!cursor.hasPostfixPosition(), "A cursor cannot specify both position and postfix position.");
        InvalidConversionException.checkConversion(!cursor.hasAbsolutePosition(), "A cursor cannot specify both position and absolute position.");
        Position pos = cursor.getPosition();
        if (pos.hasStartKey()) {
            IndexPosition indexPos = cursor.getMutableAbsolutePosition();
            indexPos.setKeyAsBytes(pos.getStartKeyAsBytes());
            if (pos.hasStartInclusive()) {
                indexPos.setBefore(pos.isStartInclusive());
            }
            if (pos.hasBeforeAscending()) {
                indexPos.setBeforeAscending(pos.isBeforeAscending());
            }
        } else if (pos.hasKey() || pos.indexValueSize() > 0) {
            IndexPostfix postfixPos = cursor.getMutablePostfixPosition();
            for (PositionIndexValue value : pos.indexValues()) {
                IndexPostfix_IndexValue indexValue = postfixPos.addIndexValue().setPropertyName(value.getProperty());
                indexValue.getMutableValue().mergeFrom(value.getValue());
            }
            if (pos.hasKey()) {
                postfixPos.getMutableKey().mergeFrom(pos.getKey());
            }
            if (pos.hasStartInclusive()) {
                postfixPos.setBefore(pos.isStartInclusive());
            }
            if (pos.hasBeforeAscending()) {
                postfixPos.setBeforeAscending(pos.isBeforeAscending());
            }
        }
        cursor.clearPosition();
    }
    // Next, populate before_ascending or before.
    if (isEmpty(cursor)) {
        return;
    } else if (cursor.hasAbsolutePosition()) {
        IndexPosition indexPosition = cursor.getAbsolutePosition();
        if (indexPosition.hasBeforeAscending()) {
            setBefore(indexPosition, firstSortDirection);
        } else {
            setBeforeAscending(indexPosition, firstSortDirection);
        }
    } else if (cursor.hasPostfixPosition()) {
        IndexPostfix indexPostfix = cursor.getPostfixPosition();
        if (indexPostfix.hasBeforeAscending()) {
            setBefore(indexPostfix, firstSortDirection);
        } else {
            setBeforeAscending(indexPostfix, firstSortDirection);
        }
    }
}
Also used : IndexPostfix(com.google.storage.onestore.v3.OnestoreEntity.IndexPostfix) IndexPosition(com.google.storage.onestore.v3.OnestoreEntity.IndexPosition) Position(com.google.apphosting.datastore.DatastoreV3Pb.CompiledCursor.Position) PositionIndexValue(com.google.apphosting.datastore.DatastoreV3Pb.CompiledCursor.PositionIndexValue) IndexPosition(com.google.storage.onestore.v3.OnestoreEntity.IndexPosition) IndexPostfix_IndexValue(com.google.storage.onestore.v3.OnestoreEntity.IndexPostfix_IndexValue)

Aggregations

IndexPostfix (com.google.storage.onestore.v3.OnestoreEntity.IndexPostfix)2 CompiledCursor (com.google.apphosting.datastore.DatastoreV3Pb.CompiledCursor)1 Position (com.google.apphosting.datastore.DatastoreV3Pb.CompiledCursor.Position)1 PositionIndexValue (com.google.apphosting.datastore.DatastoreV3Pb.CompiledCursor.PositionIndexValue)1 Index (com.google.storage.onestore.v3.OnestoreEntity.Index)1 Property (com.google.storage.onestore.v3.OnestoreEntity.Index.Property)1 IndexPosition (com.google.storage.onestore.v3.OnestoreEntity.IndexPosition)1 IndexPostfix_IndexValue (com.google.storage.onestore.v3.OnestoreEntity.IndexPostfix_IndexValue)1 Reference (com.google.storage.onestore.v3.OnestoreEntity.Reference)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1 Set (java.util.Set)1 Nullable (org.checkerframework.checker.nullness.qual.Nullable)1 Test (org.junit.Test)1