@Test public void preferFilterOverOrderBy() { Query queryWithoutFilter = query("a").orderBy(TestUtil.orderBy("a")); Query queryWithFilter = query("a") .orderBy(TestUtil.orderBy("a")) .orderBy(TestUtil.orderBy("b")) .filter(filter("a", ">=", true)) .filter(filter("c", "==", true)); IndexRange indexRangeWithoutFilter = extractBestIndexRange(queryWithoutFilter); IndexRange indexRangeWithFilter = extractBestIndexRange(queryWithFilter); assertThat(field("a")).isEqualTo(indexRangeWithoutFilter.getFieldPath()); assertThat(field("c")).isEqualTo(indexRangeWithFilter.getFieldPath()); }
@Nullable @VisibleForTesting static IndexRange extractBestIndexRange(Query query) { double currentSelectivity = -1; if (!query.getFilters().isEmpty()) { Filter selectedFilter = null; for (Filter currentFilter : query.getFilters()) { double estimatedSelectivity = estimateFilterSelectivity(currentFilter); if (estimatedSelectivity > currentSelectivity) { selectedFilter = currentFilter; currentSelectivity = estimatedSelectivity; } } hardAssert(selectedFilter != null, "Filter should be defined"); return convertFilterToIndexRange(selectedFilter); } else { FieldPath orderPath = query.getOrderBy().get(0).getField(); if (!orderPath.equals(FieldPath.KEY_PATH)) { return IndexRange.builder().setFieldPath(query.getOrderBy().get(0).getField()).build(); } } return null; }
IndexedQueryEngine implements QueryEngine { @Nullable @VisibleForTesting static IndexRange extractBestIndexRange(Query query) { double currentSelectivity = -1; if (!query.getFilters().isEmpty()) { Filter selectedFilter = null; for (Filter currentFilter : query.getFilters()) { double estimatedSelectivity = estimateFilterSelectivity(currentFilter); if (estimatedSelectivity > currentSelectivity) { selectedFilter = currentFilter; currentSelectivity = estimatedSelectivity; } } hardAssert(selectedFilter != null, "Filter should be defined"); return convertFilterToIndexRange(selectedFilter); } else { FieldPath orderPath = query.getOrderBy().get(0).getField(); if (!orderPath.equals(FieldPath.KEY_PATH)) { return IndexRange.builder().setFieldPath(query.getOrderBy().get(0).getField()).build(); } } return null; } }
IndexedQueryEngine implements QueryEngine { @Nullable @VisibleForTesting static IndexRange extractBestIndexRange(Query query) { double currentSelectivity = -1; if (!query.getFilters().isEmpty()) { Filter selectedFilter = null; for (Filter currentFilter : query.getFilters()) { double estimatedSelectivity = estimateFilterSelectivity(currentFilter); if (estimatedSelectivity > currentSelectivity) { selectedFilter = currentFilter; currentSelectivity = estimatedSelectivity; } } hardAssert(selectedFilter != null, "Filter should be defined"); return convertFilterToIndexRange(selectedFilter); } else { FieldPath orderPath = query.getOrderBy().get(0).getField(); if (!orderPath.equals(FieldPath.KEY_PATH)) { return IndexRange.builder().setFieldPath(query.getOrderBy().get(0).getField()).build(); } } return null; } IndexedQueryEngine(SQLiteCollectionIndex collectionIndex); }
IndexedQueryEngine implements QueryEngine { @Nullable @VisibleForTesting static IndexRange extractBestIndexRange(Query query) { double currentSelectivity = -1; if (!query.getFilters().isEmpty()) { Filter selectedFilter = null; for (Filter currentFilter : query.getFilters()) { double estimatedSelectivity = estimateFilterSelectivity(currentFilter); if (estimatedSelectivity > currentSelectivity) { selectedFilter = currentFilter; currentSelectivity = estimatedSelectivity; } } hardAssert(selectedFilter != null, "Filter should be defined"); return convertFilterToIndexRange(selectedFilter); } else { FieldPath orderPath = query.getOrderBy().get(0).getField(); if (!orderPath.equals(FieldPath.KEY_PATH)) { return IndexRange.builder().setFieldPath(query.getOrderBy().get(0).getField()).build(); } } return null; } IndexedQueryEngine(SQLiteCollectionIndex collectionIndex); @Override void setLocalDocumentsView(LocalDocumentsView localDocuments); @Override ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
      Query query,
      SnapshotVersion lastLimboFreeSnapshotVersion,
      ImmutableSortedSet<DocumentKey> remoteKeys); @Override void handleDocumentChange(MaybeDocument oldDocument, MaybeDocument newDocument); }
IndexedQueryEngine implements QueryEngine { @Nullable @VisibleForTesting static IndexRange extractBestIndexRange(Query query) { double currentSelectivity = -1; if (!query.getFilters().isEmpty()) { Filter selectedFilter = null; for (Filter currentFilter : query.getFilters()) { double estimatedSelectivity = estimateFilterSelectivity(currentFilter); if (estimatedSelectivity > currentSelectivity) { selectedFilter = currentFilter; currentSelectivity = estimatedSelectivity; } } hardAssert(selectedFilter != null, "Filter should be defined"); return convertFilterToIndexRange(selectedFilter); } else { FieldPath orderPath = query.getOrderBy().get(0).getField(); if (!orderPath.equals(FieldPath.KEY_PATH)) { return IndexRange.builder().setFieldPath(query.getOrderBy().get(0).getField()).build(); } } return null; } IndexedQueryEngine(SQLiteCollectionIndex collectionIndex); @Override void setLocalDocumentsView(LocalDocumentsView localDocuments); @Override ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
      Query query,
      SnapshotVersion lastLimboFreeSnapshotVersion,
      ImmutableSortedSet<DocumentKey> remoteKeys); @Override void handleDocumentChange(MaybeDocument oldDocument, MaybeDocument newDocument);  }