imbajin commented on code in PR #3243:
URL: https://github.com/apache/hugegraph/pull/3243#discussion_r4288294507


##########
docs/server-runtime.md:
##########
@@ -251,6 +251,34 @@ without a preceding REST graph query, and subsequent REST 
queries must remain us
 Gremlin scripts still cannot read restricted system properties such as 
`java.version`
 or disable the security manager.
 
+### Property-query index coverage
+
+A global property query such as `g.V().has("name", "alice")` or
+`g.E().has("weight", 0.5)` requires compatible indexes on every visible 
candidate
+label. A candidate declares all queried non-OLAP properties; even a label with 
no
+records requires coverage. Base edge labels have no direct records; their 
indexes
+can cover sub-labels. Shared OLAP indexes follow the graph read mode.
+
+| Candidate state | Query behavior |
+| --- | --- |
+| Every visible candidate has compatible indexes | The query combines the 
indexed results. Composite and joint index plans may serve different labels in 
the same query. |
+| A visible candidate lacks a compatible index | The query fails with 
`NoIndexException`, including when other candidates are hidden or deleting. |

Review Comment:
   🧹 Blocking: no. Summary: This row overstates when the coverage error occurs. 
Please qualify it for values that pass the existing property-type check, or 
note the invalid-value empty-result path. Evidence: queryByUserprop() returns 
an empty result at validQueryConditionValues() before checkIndexCoverage() when 
at least one index matched, so a type-mismatched query can return empty even if 
another visible candidate lacks an index.



##########
hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphIndexTransaction.java:
##########
@@ -699,6 +739,59 @@ private Set<MatchedIndex> 
collectMatchedIndexes(ConditionQuery query) {
         return matchedIndexes;
     }
 
+    private static boolean isIndexQueryCandidate(SchemaLabel label, Set<Id> 
properties) {
+        // Base edge labels describe sub-labels and have no direct records.
+        return label.properties().containsAll(properties) &&
+               !(label instanceof EdgeLabel && ((EdgeLabel) label).isFather());
+    }
+
+    private Set<Id> requiredIndexProperties(ConditionQuery query) {
+        Set<Id> requiredProperties = query.userpropKeys();
+        if (this.graph().readMode().showOlap()) {
+            // OLAP properties are shared rather than declared on every label.
+            requiredProperties.removeIf(id -> 
this.graph().propertyKey(id).olap());
+        }
+        return requiredProperties;
+    }
+
+    private void checkIndexCoverage(ConditionQuery query,
+                                    List<? extends SchemaLabel> labels,
+                                    Set<MatchedIndex> indexes) {
+        // Check at execution, before creating any lazy index iterator. Cleanup
+        // callers only need matching indexes and must not require full 
coverage.
+        Set<Id> requiredProperties = this.requiredIndexProperties(query);
+        if (requiredProperties.isEmpty()) {
+            // A shared OLAP index can match several labels, while MatchedIndex
+            // deduplicates those matches by index labels alone.
+            return;
+        }
+        Set<Id> covered = new HashSet<>();
+        for (MatchedIndex index : indexes) {
+            covered.add(index.schemaLabel().id());
+        }
+        for (SchemaLabel label : labels) {

Review Comment:
   ⚠️ Blocking: yes. Summary: A root-level negative label predicate can make 
this loop require coverage from a label the query excludes. Please include 
these label predicates when deriving coverage candidates and add a regression 
for an indexed allowed label plus an unindexed excluded label. Evidence: At 
this head TraversalUtil.canPushPositiveLabel() accepts EQ/IN labels only and 
keeps hasLabel(P.neq(...)) local; querySchemaLabels() then falls back to all 
schema labels, so g.V().hasLabel(P.neq("unindexed")).has("name", "alice") 
throws before the local filter runs.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to