try to replace given Label Scan operation and a set of Filter operations with a single Index Scan operation
| 289 | // try to replace given Label Scan operation and a set of Filter operations with |
| 290 | // a single Index Scan operation |
| 291 | void reduce_scan_op |
| 292 | ( |
| 293 | ExecutionPlan *plan, |
| 294 | NodeByLabelScan *scan |
| 295 | ) { |
| 296 | // in the multi-label case, we want to pick the label which will allow us to |
| 297 | // both utilize an index and iterate over the fewest values |
| 298 | GraphContext *gc = QueryCtx_GetGraphCtx(); |
| 299 | Graph *g = QueryCtx_GetGraph(); |
| 300 | QueryGraph *qg = scan->op.plan->query_graph; |
| 301 | |
| 302 | // find label with filtered indexed properties |
| 303 | // that has the minimum NNZ entries |
| 304 | int min_label_id; // tracks min label ID |
| 305 | uint64_t min_nnz = UINT64_MAX; // tracks min entries |
| 306 | RSIndex *rs_idx = NULL; // the index to be applied |
| 307 | OpFilter **filters = NULL; // tracks indexed filters to apply |
| 308 | uint filters_count = 0; // number of matching filters |
| 309 | const char *min_label_str = NULL; // tracks min label name |
| 310 | |
| 311 | // see if scanned node has multiple labels |
| 312 | const char *node_alias = scan->n->alias; |
| 313 | QGNode *qn = QueryGraph_GetNodeByAlias(qg, node_alias); |
| 314 | ASSERT(qn != NULL); |
| 315 | |
| 316 | uint label_count = QGNode_LabelCount(qn); |
| 317 | for(uint i = 0; i < label_count; i++) { |
| 318 | Index idx; |
| 319 | uint64_t nnz; |
| 320 | int label_id = QGNode_GetLabelID(qn, i); |
| 321 | const char *label = QGNode_GetLabel(qn, i); |
| 322 | |
| 323 | // unknown label |
| 324 | if(label_id == GRAPH_UNKNOWN_LABEL) continue; |
| 325 | |
| 326 | idx = GraphContext_GetIndexByID(gc, label_id, NULL, 0, IDX_EXACT_MATCH, |
| 327 | GETYPE_NODE); |
| 328 | |
| 329 | // no index for current label |
| 330 | if(idx == NULL) continue; |
| 331 | |
| 332 | ASSERT(Index_Enabled(idx)); |
| 333 | |
| 334 | // TODO switch to reusable array |
| 335 | OpFilter **cur_filters = _applicableFilters((OpBase *)scan, scan->n->alias, idx); |
| 336 | |
| 337 | // TODO consider heuristic which combines max |
| 338 | // number / restrictiveness of applicable filters |
| 339 | // vs. the label's NNZ? |
| 340 | uint cur_filters_count = array_len(cur_filters); |
| 341 | if(cur_filters_count == 0) { |
| 342 | // no filters |
| 343 | array_free(cur_filters); |
| 344 | continue; |
| 345 | } |
| 346 | |
| 347 | // get all applicable filter for index |
| 348 | RSIndex *cur_idx = Index_RSIndex(idx); |
no test coverage detected