Skip to content

Index Evaluation #2963

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,17 @@ public int hashCode() {

@Override
public String toString() {
return "Bound{before=" + before + ", position=" + position + '}';
StringBuilder builder = new StringBuilder();
builder.append("Bound(before=");
builder.append(before);
builder.append(", position=");
for (int i = 0; i < position.size(); i++) {
if (i > 0) {
builder.append(" and ");
}
builder.append(Values.canonicalId(position.get(i)));
}
builder.append(")");
return builder.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public String getCanonicalId() {

@Override
public String toString() {
return field.canonicalString() + " " + operator + " " + value;
return field.canonicalString() + " " + operator + " " + Values.canonicalId(value);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.firebase.firestore.model.FieldIndex;
import com.google.firebase.firestore.model.ResourcePath;
import com.google.firebase.firestore.model.Values;
import com.google.firestore.v1.ArrayValue;
import com.google.firestore.v1.Value;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -130,11 +131,19 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
FieldFilter fieldFilter = (FieldFilter) filter;
switch (fieldFilter.getOperator()) {
case LESS_THAN:
case NOT_IN:
case NOT_EQUAL:
case LESS_THAN_OR_EQUAL:
// TODO(indexing): Implement type clamping. Only field values with the same type
// should match the query.
break;
case NOT_EQUAL:
// These filters cannot be used as a lower bound. Skip.
break;
case NOT_IN:
lowestValue =
Value.newBuilder()
.setArrayValue(ArrayValue.newBuilder().addValues(Values.NULL_VALUE))
.build();
break;
case EQUAL:
case IN:
case ARRAY_CONTAINS_ANY:
Expand Down Expand Up @@ -193,23 +202,26 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
if (filter.getField().equals(segment.getFieldPath())) {
FieldFilter fieldFilter = (FieldFilter) filter;
switch (fieldFilter.getOperator()) {
case GREATER_THAN:
case NOT_IN:
case NOT_EQUAL:
case GREATER_THAN_OR_EQUAL:
// These filters cannot be used as an upper bound. Skip.
break;
case GREATER_THAN_OR_EQUAL:
case GREATER_THAN:
// TODO(indexing): Implement type clamping. Only field values with the same type
// should match the query.
break;
case EQUAL:
case IN:
case ARRAY_CONTAINS_ANY:
case ARRAY_CONTAINS:
case LESS_THAN_OR_EQUAL:
largestValue = fieldFilter.getValue();
before = true;
before = false;
break;
case LESS_THAN:
largestValue = fieldFilter.getValue();
before = false;
before = true;
break;
}
}
Expand Down Expand Up @@ -358,7 +370,7 @@ public String toString() {
if (i > 0) {
builder.append(" and ");
}
builder.append(filters.get(i).toString());
builder.append(filters.get(i));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.firebase.firestore.index;

import com.google.protobuf.ByteString;

/**
* Implements {@link DirectionalIndexByteEncoder} using {@link OrderedCodeWriter} for the actual
* encoding.
*/
public class IndexByteEncoder extends DirectionalIndexByteEncoder {
// Note: This code is copied from the backend.

private final OrderedCodeWriter orderedCode;

public IndexByteEncoder() {
this.orderedCode = new OrderedCodeWriter();
}

public void seed(byte[] encodedBytes) {
orderedCode.seed(encodedBytes);
}

@Override
public void writeBytes(ByteString val) {
orderedCode.writeBytesAscending(val);
}

@Override
public void writeString(String val) {
orderedCode.writeUtf8Ascending(val);
}

@Override
public void writeLong(long val) {
orderedCode.writeSignedLongAscending(val);
}

@Override
public void writeDouble(double val) {
orderedCode.writeDoubleAscending(val);
}

public byte[] getEncodedBytes() {
return orderedCode.encodedBytes();
}

public void reset() {
orderedCode.reset();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ public class IndexEntry {
private final int indexId;
private final byte[] indexValue;
private final String uid;
private final String documentId;
private final String documentName;

public IndexEntry(int indexId, byte[] indexValue, String uid, String documentId) {
public IndexEntry(int indexId, byte[] indexValue, String uid, String documentName) {
this.indexId = indexId;
this.indexValue = indexValue;
this.uid = uid;
this.documentId = documentId;
this.documentName = documentName;
}

public int getIndexId() {
Expand All @@ -44,7 +44,7 @@ public String getUid() {
return uid;
}

public String getDocumentId() {
return documentId;
public String getDocumentName() {
return documentName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,31 +117,31 @@ void addIndexEntry(IndexEntry entry) {
+ "index_id, "
+ "index_value, "
+ "uid, "
+ "document_id) VALUES(?, ?, ?, ?)",
+ "document_name) VALUES(?, ?, ?, ?)",
entry.getIndexId(),
entry.getIndexValue(),
entry.getUid(),
entry.getDocumentId());
entry.getDocumentName());
}

@VisibleForTesting
void removeIndexEntry(int indexId, String uid, String documentId) {
void removeIndexEntry(int indexId, String uid, String documentName) {
persistence.execute(
"DELETE FROM index_entries "
+ "WHERE index_id = ? "
+ "AND uid = ?"
+ "AND document_id = ?",
+ "AND document_name = ?",
indexId,
uid,
documentId);
documentName);
;
}

@Nullable
@VisibleForTesting
IndexEntry getIndexEntry(int indexId) {
return persistence
.query("SELECT index_value, uid, document_id FROM index_entries WHERE index_id = ?")
.query("SELECT index_value, uid, document_name FROM index_entries WHERE index_id = ?")
.binding(indexId)
.firstValue(
row ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@

package com.google.firebase.firestore.local;

import androidx.annotation.Nullable;
import com.google.firebase.firestore.core.Target;
import com.google.firebase.firestore.model.Document;
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.model.FieldIndex;
import com.google.firebase.firestore.model.ResourcePath;
import java.util.List;
import java.util.Set;

/**
* Represents a set of indexes that are used to execute queries efficiently.
Expand All @@ -41,11 +46,21 @@ public interface IndexManager {
*/
List<ResourcePath> getCollectionParents(String collectionId);

/** Adds index entries for all indexed fields in the given document. */
void addIndexEntries(Document document);

/**
* Adds a field path index.
*
* <p>Values for this index are persisted asynchronously. The index will only be used for query
* execution once values are persisted.
*/
void addFieldIndex(FieldIndex index);

/**
* Returns the documents that match the given target based on the configured indices. Returns
* {@code null} if there is no active index to serve this target.
*/
@Nullable
Set<DocumentKey> getDocumentsMatchingTarget(Target target);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.google.firebase.firestore.core.Target;
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.model.FieldIndex;
import com.google.firebase.firestore.model.FieldPath;
import com.google.firebase.firestore.model.MutableDocument;
import com.google.firebase.firestore.model.ObjectValue;
import com.google.firebase.firestore.model.SnapshotVersion;
Expand Down Expand Up @@ -309,4 +310,18 @@ public Index encodeFieldIndex(FieldIndex fieldIndex) {

return index.build();
}

public FieldIndex decodeFieldIndex(String collection_group, int indexId, Index index) {
FieldIndex fieldIndex = new FieldIndex(collection_group, indexId);
for (Index.IndexField field : index.getFieldsList()) {
fieldIndex =
fieldIndex.withAddedField(
FieldPath.fromServerFormat(field.getFieldPath()),
field.getValueModeCase().equals(Index.IndexField.ValueModeCase.ARRAY_CONFIG)
? FieldIndex.Segment.Kind.CONTAINS
: FieldIndex.Segment.Kind.ORDERED);
}

return fieldIndex;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@

import static com.google.firebase.firestore.util.Assert.hardAssert;

import androidx.annotation.Nullable;
import com.google.firebase.firestore.core.Target;
import com.google.firebase.firestore.model.Document;
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.model.FieldIndex;
import com.google.firebase.firestore.model.ResourcePath;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/** An in-memory implementation of IndexManager. */
class MemoryIndexManager implements IndexManager {
Expand All @@ -38,11 +43,23 @@ public List<ResourcePath> getCollectionParents(String collectionId) {
return collectionParentsIndex.getEntries(collectionId);
}

@Override
public void addIndexEntries(Document document) {
// Field indices are not supported with memory persistence.
}

@Override
public void addFieldIndex(FieldIndex index) {
// Field indices are not supported with memory persistence.
}

@Override
@Nullable
public Set<DocumentKey> getDocumentsMatchingTarget(Target target) {
// Field indices are not supported with memory persistence.
return null;
}

/**
* Internal implementation of the collection-parent index. Also used for in-memory caching by
* SQLiteIndexManager and initial index population in SQLiteSchema.
Expand Down
Loading