Skip to content

Commit da62838

Browse files
Index Evaluation (#2963)
1 parent 191700a commit da62838

File tree

19 files changed

+735
-67
lines changed

19 files changed

+735
-67
lines changed

firebase-firestore/src/main/java/com/google/firebase/firestore/core/Bound.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,17 @@ public int hashCode() {
132132

133133
@Override
134134
public String toString() {
135-
return "Bound{before=" + before + ", position=" + position + '}';
135+
StringBuilder builder = new StringBuilder();
136+
builder.append("Bound(before=");
137+
builder.append(before);
138+
builder.append(", position=");
139+
for (int i = 0; i < position.size(); i++) {
140+
if (i > 0) {
141+
builder.append(" and ");
142+
}
143+
builder.append(Values.canonicalId(position.get(i)));
144+
}
145+
builder.append(")");
146+
return builder.toString();
136147
}
137148
}

firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public String getCanonicalId() {
137137

138138
@Override
139139
public String toString() {
140-
return field.canonicalString() + " " + operator + " " + value;
140+
return field.canonicalString() + " " + operator + " " + Values.canonicalId(value);
141141
}
142142

143143
@Override

firebase-firestore/src/main/java/com/google/firebase/firestore/core/Target.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.firebase.firestore.model.FieldIndex;
2121
import com.google.firebase.firestore.model.ResourcePath;
2222
import com.google.firebase.firestore.model.Values;
23+
import com.google.firestore.v1.ArrayValue;
2324
import com.google.firestore.v1.Value;
2425
import java.util.ArrayList;
2526
import java.util.List;
@@ -130,11 +131,19 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
130131
FieldFilter fieldFilter = (FieldFilter) filter;
131132
switch (fieldFilter.getOperator()) {
132133
case LESS_THAN:
133-
case NOT_IN:
134-
case NOT_EQUAL:
135134
case LESS_THAN_OR_EQUAL:
135+
// TODO(indexing): Implement type clamping. Only field values with the same type
136+
// should match the query.
137+
break;
138+
case NOT_EQUAL:
136139
// These filters cannot be used as a lower bound. Skip.
137140
break;
141+
case NOT_IN:
142+
lowestValue =
143+
Value.newBuilder()
144+
.setArrayValue(ArrayValue.newBuilder().addValues(Values.NULL_VALUE))
145+
.build();
146+
break;
138147
case EQUAL:
139148
case IN:
140149
case ARRAY_CONTAINS_ANY:
@@ -193,23 +202,26 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
193202
if (filter.getField().equals(segment.getFieldPath())) {
194203
FieldFilter fieldFilter = (FieldFilter) filter;
195204
switch (fieldFilter.getOperator()) {
196-
case GREATER_THAN:
197205
case NOT_IN:
198206
case NOT_EQUAL:
199-
case GREATER_THAN_OR_EQUAL:
200207
// These filters cannot be used as an upper bound. Skip.
201208
break;
209+
case GREATER_THAN_OR_EQUAL:
210+
case GREATER_THAN:
211+
// TODO(indexing): Implement type clamping. Only field values with the same type
212+
// should match the query.
213+
break;
202214
case EQUAL:
203215
case IN:
204216
case ARRAY_CONTAINS_ANY:
205217
case ARRAY_CONTAINS:
206218
case LESS_THAN_OR_EQUAL:
207219
largestValue = fieldFilter.getValue();
208-
before = true;
220+
before = false;
209221
break;
210222
case LESS_THAN:
211223
largestValue = fieldFilter.getValue();
212-
before = false;
224+
before = true;
213225
break;
214226
}
215227
}
@@ -358,7 +370,7 @@ public String toString() {
358370
if (i > 0) {
359371
builder.append(" and ");
360372
}
361-
builder.append(filters.get(i).toString());
373+
builder.append(filters.get(i));
362374
}
363375
}
364376

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore.index;
16+
17+
import com.google.protobuf.ByteString;
18+
19+
/**
20+
* Implements {@link DirectionalIndexByteEncoder} using {@link OrderedCodeWriter} for the actual
21+
* encoding.
22+
*/
23+
public class IndexByteEncoder extends DirectionalIndexByteEncoder {
24+
// Note: This code is copied from the backend.
25+
26+
private final OrderedCodeWriter orderedCode;
27+
28+
public IndexByteEncoder() {
29+
this.orderedCode = new OrderedCodeWriter();
30+
}
31+
32+
public void seed(byte[] encodedBytes) {
33+
orderedCode.seed(encodedBytes);
34+
}
35+
36+
@Override
37+
public void writeBytes(ByteString val) {
38+
orderedCode.writeBytesAscending(val);
39+
}
40+
41+
@Override
42+
public void writeString(String val) {
43+
orderedCode.writeUtf8Ascending(val);
44+
}
45+
46+
@Override
47+
public void writeLong(long val) {
48+
orderedCode.writeSignedLongAscending(val);
49+
}
50+
51+
@Override
52+
public void writeDouble(double val) {
53+
orderedCode.writeDoubleAscending(val);
54+
}
55+
56+
public byte[] getEncodedBytes() {
57+
return orderedCode.encodedBytes();
58+
}
59+
60+
public void reset() {
61+
orderedCode.reset();
62+
}
63+
}

firebase-firestore/src/main/java/com/google/firebase/firestore/index/IndexEntry.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ public class IndexEntry {
2323
private final int indexId;
2424
private final byte[] indexValue;
2525
private final String uid;
26-
private final String documentId;
26+
private final String documentName;
2727

28-
public IndexEntry(int indexId, byte[] indexValue, String uid, String documentId) {
28+
public IndexEntry(int indexId, byte[] indexValue, String uid, String documentName) {
2929
this.indexId = indexId;
3030
this.indexValue = indexValue;
3131
this.uid = uid;
32-
this.documentId = documentId;
32+
this.documentName = documentName;
3333
}
3434

3535
public int getIndexId() {
@@ -44,7 +44,7 @@ public String getUid() {
4444
return uid;
4545
}
4646

47-
public String getDocumentId() {
48-
return documentId;
47+
public String getDocumentName() {
48+
return documentName;
4949
}
5050
}

firebase-firestore/src/main/java/com/google/firebase/firestore/local/IndexBackfiller.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,31 +117,31 @@ void addIndexEntry(IndexEntry entry) {
117117
+ "index_id, "
118118
+ "index_value, "
119119
+ "uid, "
120-
+ "document_id) VALUES(?, ?, ?, ?)",
120+
+ "document_name) VALUES(?, ?, ?, ?)",
121121
entry.getIndexId(),
122122
entry.getIndexValue(),
123123
entry.getUid(),
124-
entry.getDocumentId());
124+
entry.getDocumentName());
125125
}
126126

127127
@VisibleForTesting
128-
void removeIndexEntry(int indexId, String uid, String documentId) {
128+
void removeIndexEntry(int indexId, String uid, String documentName) {
129129
persistence.execute(
130130
"DELETE FROM index_entries "
131131
+ "WHERE index_id = ? "
132132
+ "AND uid = ?"
133-
+ "AND document_id = ?",
133+
+ "AND document_name = ?",
134134
indexId,
135135
uid,
136-
documentId);
136+
documentName);
137137
;
138138
}
139139

140140
@Nullable
141141
@VisibleForTesting
142142
IndexEntry getIndexEntry(int indexId) {
143143
return persistence
144-
.query("SELECT index_value, uid, document_id FROM index_entries WHERE index_id = ?")
144+
.query("SELECT index_value, uid, document_name FROM index_entries WHERE index_id = ?")
145145
.binding(indexId)
146146
.firstValue(
147147
row ->

firebase-firestore/src/main/java/com/google/firebase/firestore/local/IndexManager.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@
1414

1515
package com.google.firebase.firestore.local;
1616

17+
import androidx.annotation.Nullable;
18+
import com.google.firebase.firestore.core.Target;
19+
import com.google.firebase.firestore.model.Document;
20+
import com.google.firebase.firestore.model.DocumentKey;
1721
import com.google.firebase.firestore.model.FieldIndex;
1822
import com.google.firebase.firestore.model.ResourcePath;
1923
import java.util.List;
24+
import java.util.Set;
2025

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

49+
/** Adds index entries for all indexed fields in the given document. */
50+
void addIndexEntries(Document document);
51+
4452
/**
4553
* Adds a field path index.
4654
*
4755
* <p>Values for this index are persisted asynchronously. The index will only be used for query
4856
* execution once values are persisted.
4957
*/
5058
void addFieldIndex(FieldIndex index);
59+
60+
/**
61+
* Returns the documents that match the given target based on the configured indices. Returns
62+
* {@code null} if there is no active index to serve this target.
63+
*/
64+
@Nullable
65+
Set<DocumentKey> getDocumentsMatchingTarget(Target target);
5166
}

firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalSerializer.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.google.firebase.firestore.core.Target;
2424
import com.google.firebase.firestore.model.DocumentKey;
2525
import com.google.firebase.firestore.model.FieldIndex;
26+
import com.google.firebase.firestore.model.FieldPath;
2627
import com.google.firebase.firestore.model.MutableDocument;
2728
import com.google.firebase.firestore.model.ObjectValue;
2829
import com.google.firebase.firestore.model.SnapshotVersion;
@@ -309,4 +310,18 @@ public Index encodeFieldIndex(FieldIndex fieldIndex) {
309310

310311
return index.build();
311312
}
313+
314+
public FieldIndex decodeFieldIndex(String collection_group, int indexId, Index index) {
315+
FieldIndex fieldIndex = new FieldIndex(collection_group, indexId);
316+
for (Index.IndexField field : index.getFieldsList()) {
317+
fieldIndex =
318+
fieldIndex.withAddedField(
319+
FieldPath.fromServerFormat(field.getFieldPath()),
320+
field.getValueModeCase().equals(Index.IndexField.ValueModeCase.ARRAY_CONFIG)
321+
? FieldIndex.Segment.Kind.CONTAINS
322+
: FieldIndex.Segment.Kind.ORDERED);
323+
}
324+
325+
return fieldIndex;
326+
}
312327
}

firebase-firestore/src/main/java/com/google/firebase/firestore/local/MemoryIndexManager.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,18 @@
1515

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

18+
import androidx.annotation.Nullable;
19+
import com.google.firebase.firestore.core.Target;
20+
import com.google.firebase.firestore.model.Document;
21+
import com.google.firebase.firestore.model.DocumentKey;
1822
import com.google.firebase.firestore.model.FieldIndex;
1923
import com.google.firebase.firestore.model.ResourcePath;
2024
import java.util.ArrayList;
2125
import java.util.Collections;
2226
import java.util.HashMap;
2327
import java.util.HashSet;
2428
import java.util.List;
29+
import java.util.Set;
2530

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

46+
@Override
47+
public void addIndexEntries(Document document) {
48+
// Field indices are not supported with memory persistence.
49+
}
50+
4151
@Override
4252
public void addFieldIndex(FieldIndex index) {
4353
// Field indices are not supported with memory persistence.
4454
}
4555

56+
@Override
57+
@Nullable
58+
public Set<DocumentKey> getDocumentsMatchingTarget(Target target) {
59+
// Field indices are not supported with memory persistence.
60+
return null;
61+
}
62+
4663
/**
4764
* Internal implementation of the collection-parent index. Also used for in-memory caching by
4865
* SQLiteIndexManager and initial index population in SQLiteSchema.

0 commit comments

Comments
 (0)