github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/query/query.go (about) 1 /* 2 * Copyright 2015-2018 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package query 18 19 import ( 20 "context" 21 "fmt" 22 "math" 23 "sort" 24 "strconv" 25 "strings" 26 "time" 27 28 "github.com/golang/glog" 29 "github.com/pkg/errors" 30 otrace "go.opencensus.io/trace" 31 "google.golang.org/grpc/metadata" 32 33 "github.com/dgraph-io/dgo/protos/api" 34 "github.com/dgraph-io/dgraph/algo" 35 "github.com/dgraph-io/dgraph/gql" 36 "github.com/dgraph-io/dgraph/protos/pb" 37 "github.com/dgraph-io/dgraph/schema" 38 "github.com/dgraph-io/dgraph/types" 39 "github.com/dgraph-io/dgraph/types/facets" 40 "github.com/dgraph-io/dgraph/worker" 41 "github.com/dgraph-io/dgraph/x" 42 ) 43 44 /* 45 * QUERY: 46 * Let's take this query from GraphQL as example: 47 * { 48 * me { 49 * id 50 * firstName 51 * lastName 52 * birthday { 53 * month 54 * day 55 * } 56 * friends { 57 * name 58 * } 59 * } 60 * } 61 * 62 * REPRESENTATION: 63 * This would be represented in SubGraph format pb.y, as such: 64 * SubGraph [result uid = me] 65 * | 66 * Children 67 * | 68 * --> SubGraph [Attr = "xid"] 69 * --> SubGraph [Attr = "firstName"] 70 * --> SubGraph [Attr = "lastName"] 71 * --> SubGraph [Attr = "birthday"] 72 * | 73 * Children 74 * | 75 * --> SubGraph [Attr = "month"] 76 * --> SubGraph [Attr = "day"] 77 * --> SubGraph [Attr = "friends"] 78 * | 79 * Children 80 * | 81 * --> SubGraph [Attr = "name"] 82 * 83 * ALGORITHM: 84 * This is a rough and simple algorithm of how to process this SubGraph query 85 * and populate the results: 86 * 87 * For a given entity, a new SubGraph can be started off with NewGraph(id). 88 * Given a SubGraph, is the Query field empty? [Step a] 89 * - If no, run (or send it to server serving the attribute) query 90 * and populate result. 91 * Iterate over children and copy Result Uids to child Query Uids. 92 * Set Attr. Then for each child, use goroutine to run Step:a. 93 * Wait for goroutines to finish. 94 * Return errors, if any. 95 */ 96 97 // Latency is used to keep track of the latency involved in parsing and processing 98 // the query. It also contains information about the time it took to convert the 99 // result into a format(JSON/Protocol Buffer) that the client expects. 100 type Latency struct { 101 Start time.Time `json:"-"` 102 Parsing time.Duration `json:"query_parsing"` 103 AssignTimestamp time.Duration `json:"assign_timestamp"` 104 Processing time.Duration `json:"processing"` 105 Json time.Duration `json:"json_conversion"` 106 } 107 108 // params contains the list of parameters required to execute a SubGraph. 109 type params struct { 110 Alias string 111 Count int // Value of "first" parameter in the query. 112 Offset int // Value of offset parameter. 113 AfterUID uint64 // Value of after 114 DoCount bool // True if count of predicate is requested instead of the value of predicate. 115 GetUid bool // True if uid should be returned. Used for debug requests. 116 Order []*pb.Order // List of predicates to sort by and the sort order. 117 Langs []string // languages and their preference order for looking up a predicate value 118 119 // Facet tells us about the requested facets and their aliases. 120 Facet *pb.FacetParams 121 // FacetOrder has the name of the facet by which the results should be sorted. 122 FacetOrder string 123 FacetOrderDesc bool 124 125 // The name of the variable defined in this SubGraph. 126 // for e.g. in x as name, this would be x 127 Var string 128 // map of predicate to the facet variable alias 129 // for e.g. @facets(L1 as weight) the map would be { "weight": "L1" } 130 FacetVar map[string]string 131 // The list of variables required by this SubGraph along with their type 132 NeedsVar []gql.VarContext 133 134 // ParentVars is a map of variables passed down recursively to children of a SubGraph in a query 135 // block. These are used to filter uids defined in a parent using a variable. 136 // TODO (pawan) - This can potentially be simplified to a map[string]*pb.List since we don't 137 // support reading from value variables defined in the parent and other fields that are part 138 // of varValue. 139 ParentVars map[string]varValue 140 141 // mapping of uid to values. This is populated into a SubGraph from a value variable that is 142 // part of req.Vars. This value variable variable would have been defined in some other query. 143 uidToVal map[uint64]types.Val 144 145 // directives 146 Normalize bool // True if @normalize directive is specified 147 Recurse bool // True if @recurse directive is specified 148 RecurseArgs gql.RecurseArgs 149 150 Cascade bool // True if @cascade directive is specified 151 IgnoreReflex bool // True if ignorereflex directive is specified. 152 153 // ShortestPathArgs contains the from and to functions to execute a shortest path query. 154 // The function is evaluated and the value of the nodes between which to run the shortest path 155 // query is stored in From and To. 156 ShortestPathArgs gql.ShortestPathArgs 157 From uint64 158 To uint64 159 numPaths int // used for k-shortest path query to specify number of paths to return. 160 MaxWeight float64 161 MinWeight float64 162 163 // used by recurse and shortest path queries to specify the graph depth to explore. 164 ExploreDepth uint64 165 166 isInternal bool // Determines if processTask has to be called or not. 167 ignoreResult bool // Node results are ignored. 168 Expand string // Value is either _all_/variable-name or empty. 169 170 isGroupBy bool // True if @groupby is specified. 171 groupbyAttrs []gql.GroupByAttr // list of attributes to groupby. 172 173 uidCount bool 174 uidCountAlias string 175 parentIds []uint64 // This is a stack that is maintained and passed down to children. 176 IsEmpty bool // Won't have any SrcUids or DestUids. Only used to get aggregated vars 177 expandAll bool // expand all languages 178 shortest bool 179 } 180 181 type pathMetadata struct { 182 weight float64 // Total weight of the path. 183 } 184 185 // Function holds the information about gql functions. 186 type Function struct { 187 Name string // Specifies the name of the function. 188 Args []gql.Arg // Contains the arguments of the function. 189 IsCount bool // gt(count(friends),0) 190 IsValueVar bool // eq(val(s), 10) 191 IsLenVar bool // eq(len(s), 10) 192 } 193 194 // SubGraph is the way to represent data. It contains both the request parameters and the response. 195 // Once generated, this can then be encoded to other client convenient formats, like GraphQL / JSON. 196 type SubGraph struct { 197 ReadTs uint64 198 Cache int 199 Attr string 200 UnknownAttr bool 201 // read only parameters which are populated before the execution of the query and are used to 202 // execute this query. 203 Params params 204 205 // count stores the count of an edge (predicate). There would be one value corresponding to each 206 // uid in SrcUIDs. 207 counts []uint32 208 // valueMatrix is a slice of ValueList. If this SubGraph is for a scalar predicate type, then 209 // there would be one list for each uid in SrcUIDs storing the value of the predicate. 210 // The individual elements of the slice are a ValueList because we support scalar predicates 211 // of list type. For non-list type scalar predicates, there would be only one value in every 212 // ValueList. 213 valueMatrix []*pb.ValueList 214 // uidMatrix is a slice of List. There would be one List corresponding to each uid in SrcUIDs. 215 // In graph terms, a list is a slice of outgoing edges from a node. 216 uidMatrix []*pb.List 217 218 // facetsMatrix contains the facet values. There would a list corresponding to each uid in 219 // uidMatrix. 220 facetsMatrix []*pb.FacetsList 221 ExpandPreds []*pb.ValueList 222 GroupbyRes []*groupResults // one result for each uid list. 223 LangTags []*pb.LangList 224 225 // SrcUIDs is a list of unique source UIDs. They are always copies of destUIDs 226 // of parent nodes in GraphQL structure. 227 SrcUIDs *pb.List 228 // SrcFunc specified using func. Should only be non-nil at root. At other levels, 229 // filters are used. 230 SrcFunc *Function 231 232 FilterOp string 233 Filters []*SubGraph // List of filters specified at the current node. 234 facetsFilter *pb.FilterTree 235 MathExp *mathTree 236 Children []*SubGraph // children of the current node, should be empty for leaf nodes. 237 238 // destUIDs is a list of destination UIDs, after applying filters, pagination. 239 DestUIDs *pb.List 240 List bool // whether predicate is of list type 241 242 pathMeta *pathMetadata 243 } 244 245 func (sg *SubGraph) recurse(set func(sg *SubGraph)) { 246 set(sg) 247 for _, child := range sg.Children { 248 child.recurse(set) 249 } 250 for _, filter := range sg.Filters { 251 filter.recurse(set) 252 } 253 } 254 255 // IsGroupBy returns whether this subgraph is part of a groupBy query. 256 func (sg *SubGraph) IsGroupBy() bool { 257 return sg.Params.isGroupBy 258 } 259 260 // IsInternal returns whether this subgraph is marked as internal. 261 func (sg *SubGraph) IsInternal() bool { 262 return sg.Params.isInternal 263 } 264 265 func (sg *SubGraph) createSrcFunction(gf *gql.Function) { 266 if gf == nil { 267 return 268 } 269 270 sg.SrcFunc = &Function{ 271 Name: gf.Name, 272 Args: append(gf.Args[:0:0], gf.Args...), 273 IsCount: gf.IsCount, 274 IsValueVar: gf.IsValueVar, 275 IsLenVar: gf.IsLenVar, 276 } 277 278 // type function is just an alias for eq(type, "dgraph.type"). 279 if gf.Name == "type" { 280 sg.Attr = "dgraph.type" 281 sg.SrcFunc.Name = "eq" 282 sg.SrcFunc.IsCount = false 283 sg.SrcFunc.IsValueVar = false 284 sg.SrcFunc.IsLenVar = false 285 return 286 } 287 288 if gf.Lang != "" { 289 sg.Params.Langs = append(sg.Params.Langs, gf.Lang) 290 } 291 } 292 293 // DebugPrint prints out the SubGraph tree in a nice format for debugging purposes. 294 func (sg *SubGraph) DebugPrint(prefix string) { 295 var src, dst int 296 if sg.SrcUIDs != nil { 297 src = len(sg.SrcUIDs.Uids) 298 } 299 if sg.DestUIDs != nil { 300 dst = len(sg.DestUIDs.Uids) 301 } 302 glog.Infof("%s[%q Alias:%q Func:%v SrcSz:%v Op:%q DestSz:%v IsCount: %v ValueSz:%v]\n", 303 prefix, sg.Attr, sg.Params.Alias, sg.SrcFunc, src, sg.FilterOp, 304 dst, sg.Params.DoCount, len(sg.valueMatrix)) 305 for _, f := range sg.Filters { 306 f.DebugPrint(prefix + "|-f->") 307 } 308 for _, c := range sg.Children { 309 c.DebugPrint(prefix + "|->") 310 } 311 } 312 313 // getValue gets the value from the task. 314 func getValue(tv *pb.TaskValue) (types.Val, error) { 315 vID := types.TypeID(tv.ValType) 316 val := types.ValueForType(vID) 317 val.Value = tv.Val 318 return val, nil 319 } 320 321 var ( 322 // ErrEmptyVal is returned when a value is empty. 323 ErrEmptyVal = errors.New("Query: harmless error, e.g. task.Val is nil") 324 // ErrWrongAgg is returned when value aggregation is attempted in the root level of a query. 325 ErrWrongAgg = errors.New("Wrong level for var aggregation") 326 ) 327 328 func (sg *SubGraph) isSimilar(ssg *SubGraph) bool { 329 if sg.Attr != ssg.Attr { 330 return false 331 } 332 if len(sg.Params.Langs) != len(ssg.Params.Langs) { 333 return false 334 } 335 for i := 0; i < len(sg.Params.Langs) && i < len(ssg.Params.Langs); i++ { 336 if sg.Params.Langs[i] != ssg.Params.Langs[i] { 337 return false 338 } 339 } 340 if sg.Params.DoCount { 341 return ssg.Params.DoCount 342 } 343 if ssg.Params.DoCount { 344 return false 345 } 346 if sg.SrcFunc != nil { 347 if ssg.SrcFunc != nil && sg.SrcFunc.Name == ssg.SrcFunc.Name { 348 return true 349 } 350 return false 351 } 352 return true 353 } 354 355 func isEmptyIneqFnWithVar(sg *SubGraph) bool { 356 return sg.SrcFunc != nil && isInequalityFn(sg.SrcFunc.Name) && len(sg.SrcFunc.Args) == 0 && 357 len(sg.Params.NeedsVar) > 0 358 } 359 360 // convert from task.Val to types.Value, based on schema appropriate type 361 // is already set in api.Value 362 func convertWithBestEffort(tv *pb.TaskValue, attr string) (types.Val, error) { 363 // value would be in binary format with appropriate type 364 v, _ := getValue(tv) 365 if !v.Tid.IsScalar() { 366 return v, errors.Errorf("Leaf predicate:'%v' must be a scalar.", attr) 367 } 368 369 // creates appropriate type from binary format 370 sv, err := types.Convert(v, v.Tid) 371 x.Checkf(err, "Error while interpreting appropriate type from binary") 372 return sv, nil 373 } 374 375 func mathCopy(dst *mathTree, src *gql.MathTree) error { 376 // Either we'll have an operation specified, or the function specified. 377 dst.Const = src.Const 378 dst.Fn = src.Fn 379 dst.Val = src.Val 380 dst.Var = src.Var 381 382 for _, mc := range src.Child { 383 child := &mathTree{} 384 if err := mathCopy(child, mc); err != nil { 385 return err 386 } 387 dst.Child = append(dst.Child, child) 388 } 389 return nil 390 } 391 392 func filterCopy(sg *SubGraph, ft *gql.FilterTree) error { 393 // Either we'll have an operation specified, or the function specified. 394 if len(ft.Op) > 0 { 395 sg.FilterOp = ft.Op 396 } else { 397 sg.Attr = ft.Func.Attr 398 if !isValidFuncName(ft.Func.Name) { 399 return errors.Errorf("Invalid function name: %s", ft.Func.Name) 400 } 401 402 if isUidFnWithoutVar(ft.Func) { 403 sg.SrcFunc = &Function{Name: ft.Func.Name} 404 if err := sg.populate(ft.Func.UID); err != nil { 405 return err 406 } 407 } else { 408 if ft.Func.Attr == "uid" { 409 return errors.Errorf(`Argument cannot be "uid"`) 410 } 411 sg.createSrcFunction(ft.Func) 412 sg.Params.NeedsVar = append(sg.Params.NeedsVar, ft.Func.NeedsVar...) 413 } 414 } 415 for _, ftc := range ft.Child { 416 child := &SubGraph{} 417 if err := filterCopy(child, ftc); err != nil { 418 return err 419 } 420 sg.Filters = append(sg.Filters, child) 421 } 422 return nil 423 } 424 425 func uniqueKey(gchild *gql.GraphQuery) string { 426 key := gchild.Attr 427 if gchild.Func != nil { 428 key += fmt.Sprintf("%v", gchild.Func) 429 } 430 // This is the case when we ask for a variable. 431 if gchild.Attr == "val" { 432 // E.g. a as age, result is returned as var(a) 433 if gchild.Var != "" && gchild.Var != "val" { 434 key = fmt.Sprintf("val(%v)", gchild.Var) 435 } else if len(gchild.NeedsVar) > 0 { 436 // For var(s) 437 key = fmt.Sprintf("val(%v)", gchild.NeedsVar[0].Name) 438 } 439 440 // Could be min(var(x)) && max(var(x)) 441 if gchild.Func != nil { 442 key += gchild.Func.Name 443 } 444 } 445 if gchild.IsCount { // ignore count subgraphs.. 446 key += "count" 447 } 448 if len(gchild.Langs) > 0 { 449 key += fmt.Sprintf("%v", gchild.Langs) 450 } 451 if gchild.MathExp != nil { 452 // We would only be here if Alias is empty, so Var would be non 453 // empty because MathExp should have atleast one of them. 454 key = fmt.Sprintf("val(%+v)", gchild.Var) 455 } 456 if gchild.IsGroupby { 457 key += "groupby" 458 } 459 return key 460 } 461 462 func treeCopy(gq *gql.GraphQuery, sg *SubGraph) error { 463 // Typically you act on the current node, and leave recursion to deal with 464 // children. But, in this case, we don't want to muck with the current 465 // node, because of the way we're dealing with the root node. 466 // So, we work on the children, and then recurse for grand children. 467 attrsSeen := make(map[string]struct{}) 468 469 for _, gchild := range gq.Children { 470 if sg.Params.Alias == "shortest" && gchild.Expand != "" { 471 return errors.Errorf("expand() not allowed inside shortest") 472 } 473 474 key := "" 475 if gchild.Alias != "" { 476 key = gchild.Alias 477 } else { 478 key = uniqueKey(gchild) 479 } 480 if _, ok := attrsSeen[key]; ok { 481 return errors.Errorf("%s not allowed multiple times in same sub-query.", 482 key) 483 } 484 attrsSeen[key] = struct{}{} 485 486 args := params{ 487 Alias: gchild.Alias, 488 Cascade: sg.Params.Cascade, 489 Expand: gchild.Expand, 490 Facet: gchild.Facets, 491 FacetOrder: gchild.FacetOrder, 492 FacetOrderDesc: gchild.FacetDesc, 493 FacetVar: gchild.FacetVar, 494 GetUid: sg.Params.GetUid, 495 IgnoreReflex: sg.Params.IgnoreReflex, 496 Langs: gchild.Langs, 497 NeedsVar: append(gchild.NeedsVar[:0:0], gchild.NeedsVar...), 498 Normalize: sg.Params.Normalize, 499 Order: gchild.Order, 500 Var: gchild.Var, 501 groupbyAttrs: gchild.GroupbyAttrs, 502 isGroupBy: gchild.IsGroupby, 503 isInternal: gchild.IsInternal, 504 uidCount: gchild.UidCount, 505 uidCountAlias: gchild.UidCountAlias, 506 } 507 508 if gchild.IsCount { 509 if len(gchild.Children) != 0 { 510 return errors.New("Node with count cannot have child attributes") 511 } 512 args.DoCount = true 513 } 514 515 for argk := range gchild.Args { 516 if !isValidArg(argk) { 517 return errors.Errorf("Invalid argument: %s", argk) 518 } 519 } 520 if err := args.fill(gchild); err != nil { 521 return err 522 } 523 524 if len(args.Order) != 0 && len(args.FacetOrder) != 0 { 525 return errors.Errorf("Cannot specify order at both args and facets") 526 } 527 528 dst := &SubGraph{ 529 Attr: gchild.Attr, 530 Params: args, 531 } 532 if gchild.MathExp != nil { 533 mathExp := &mathTree{} 534 if err := mathCopy(mathExp, gchild.MathExp); err != nil { 535 return err 536 } 537 dst.MathExp = mathExp 538 } 539 540 if gchild.Func != nil && 541 (gchild.Func.IsAggregator() || gchild.Func.IsPasswordVerifier()) { 542 if len(gchild.Children) != 0 { 543 return errors.Errorf("Node with %q cant have child attr", gchild.Func.Name) 544 } 545 // embedded filter will cause ambiguous output like following, 546 // director.film @filter(gt(initial_release_date, "2016")) { 547 // min(initial_release_date @filter(gt(initial_release_date, "1986")) 548 // } 549 if gchild.Filter != nil { 550 return errors.Errorf( 551 "Node with %q cant have filter, please place the filter on the upper level", 552 gchild.Func.Name) 553 } 554 if gchild.Func.Attr == "uid" { 555 return errors.Errorf(`Argument cannot be "uid"`) 556 } 557 dst.createSrcFunction(gchild.Func) 558 } 559 560 if gchild.Filter != nil { 561 dstf := &SubGraph{} 562 if err := filterCopy(dstf, gchild.Filter); err != nil { 563 return err 564 } 565 dst.Filters = append(dst.Filters, dstf) 566 } 567 568 if gchild.FacetsFilter != nil { 569 facetsFilter, err := toFacetsFilter(gchild.FacetsFilter) 570 if err != nil { 571 return err 572 } 573 dst.facetsFilter = facetsFilter 574 } 575 576 sg.Children = append(sg.Children, dst) 577 if err := treeCopy(gchild, dst); err != nil { 578 return err 579 } 580 } 581 return nil 582 } 583 584 func (args *params) fill(gq *gql.GraphQuery) error { 585 if v, ok := gq.Args["offset"]; ok { 586 offset, err := strconv.ParseInt(v, 0, 32) 587 if err != nil { 588 return err 589 } 590 args.Offset = int(offset) 591 } 592 if v, ok := gq.Args["after"]; ok { 593 after, err := strconv.ParseUint(v, 0, 64) 594 if err != nil { 595 return err 596 } 597 args.AfterUID = after 598 } 599 600 if args.Alias == "shortest" { 601 if v, ok := gq.Args["depth"]; ok { 602 depth, err := strconv.ParseUint(v, 0, 64) 603 if err != nil { 604 return err 605 } 606 args.ExploreDepth = depth 607 } 608 609 if v, ok := gq.Args["numpaths"]; ok { 610 numPaths, err := strconv.ParseUint(v, 0, 64) 611 if err != nil { 612 return err 613 } 614 args.numPaths = int(numPaths) 615 } 616 617 if v, ok := gq.Args["maxweight"]; ok { 618 maxWeight, err := strconv.ParseFloat(v, 64) 619 if err != nil { 620 return err 621 } 622 args.MaxWeight = maxWeight 623 } else if !ok { 624 args.MaxWeight = math.MaxFloat64 625 } 626 627 if v, ok := gq.Args["minweight"]; ok { 628 minWeight, err := strconv.ParseFloat(v, 64) 629 if err != nil { 630 return err 631 } 632 args.MinWeight = minWeight 633 } else if !ok { 634 args.MinWeight = -math.MaxFloat64 635 } 636 637 if gq.ShortestPathArgs.From == nil || gq.ShortestPathArgs.To == nil { 638 return errors.Errorf("from/to can't be nil for shortest path") 639 } 640 if len(gq.ShortestPathArgs.From.UID) > 0 { 641 args.From = gq.ShortestPathArgs.From.UID[0] 642 } 643 if len(gq.ShortestPathArgs.To.UID) > 0 { 644 args.To = gq.ShortestPathArgs.To.UID[0] 645 } 646 } 647 648 if v, ok := gq.Args["first"]; ok { 649 first, err := strconv.ParseInt(v, 0, 32) 650 if err != nil { 651 return err 652 } 653 args.Count = int(first) 654 } 655 return nil 656 } 657 658 // ToSubGraph converts the GraphQuery into the pb.SubGraph instance type. 659 func ToSubGraph(ctx context.Context, gq *gql.GraphQuery) (*SubGraph, error) { 660 sg, err := newGraph(ctx, gq) 661 if err != nil { 662 return nil, err 663 } 664 err = treeCopy(gq, sg) 665 if err != nil { 666 return nil, err 667 } 668 return sg, err 669 } 670 671 // ContextKey is used to set options in the context object. 672 type ContextKey int 673 674 const ( 675 // DebugKey is the key used to toggle debug mode. 676 DebugKey ContextKey = iota 677 ) 678 679 func isDebug(ctx context.Context) bool { 680 var debug bool 681 682 // gRPC client passes information about debug as metadata. 683 if md, ok := metadata.FromIncomingContext(ctx); ok { 684 // md is a map[string][]string 685 if len(md["debug"]) > 0 { 686 // We ignore the error here, because in error case, 687 // debug would be false which is what we want. 688 debug, _ = strconv.ParseBool(md["debug"][0]) 689 } 690 } 691 692 // HTTP passes information about debug as query parameter which is attached to context. 693 d, _ := ctx.Value(DebugKey).(bool) 694 return debug || d 695 } 696 697 func (sg *SubGraph) populate(uids []uint64) error { 698 // Put sorted entries in matrix. 699 sort.Slice(uids, func(i, j int) bool { return uids[i] < uids[j] }) 700 sg.uidMatrix = []*pb.List{{Uids: uids}} 701 // User specified list may not be sorted. 702 sg.SrcUIDs = &pb.List{Uids: uids} 703 return nil 704 } 705 706 // newGraph returns the SubGraph and its task query. 707 func newGraph(ctx context.Context, gq *gql.GraphQuery) (*SubGraph, error) { 708 // This would set the Result field in SubGraph, 709 // and populate the children for attributes. 710 711 // For the root, the name to be used in result is stored in Alias, not Attr. 712 // The attr at root (if present) would stand for the source functions attr. 713 args := params{ 714 Alias: gq.Alias, 715 Cascade: gq.Cascade, 716 GetUid: isDebug(ctx), 717 IgnoreReflex: gq.IgnoreReflex, 718 IsEmpty: gq.IsEmpty, 719 Langs: gq.Langs, 720 NeedsVar: append(gq.NeedsVar[:0:0], gq.NeedsVar...), 721 Normalize: gq.Normalize, 722 Order: gq.Order, 723 ParentVars: make(map[string]varValue), 724 Recurse: gq.Recurse, 725 RecurseArgs: gq.RecurseArgs, 726 ShortestPathArgs: gq.ShortestPathArgs, 727 Var: gq.Var, 728 groupbyAttrs: gq.GroupbyAttrs, 729 isGroupBy: gq.IsGroupby, 730 uidCount: gq.UidCount, 731 uidCountAlias: gq.UidCountAlias, 732 } 733 734 for argk := range gq.Args { 735 if !isValidArg(argk) { 736 return nil, errors.Errorf("Invalid argument: %s", argk) 737 } 738 } 739 if err := args.fill(gq); err != nil { 740 return nil, errors.Wrapf(err, "while filling args") 741 } 742 743 sg := &SubGraph{Params: args} 744 745 if gq.Func != nil { 746 // Uid function doesnt have Attr. It just has a list of ids 747 if gq.Func.Attr != "uid" { 748 sg.Attr = gq.Func.Attr 749 } else { 750 // Disallow uid as attribute - issue#3110 751 if len(gq.Func.UID) == 0 { 752 return nil, errors.Errorf(`Argument cannot be "uid"`) 753 } 754 } 755 if !isValidFuncName(gq.Func.Name) { 756 return nil, errors.Errorf("Invalid function name: %s", gq.Func.Name) 757 } 758 759 sg.createSrcFunction(gq.Func) 760 } 761 762 if isUidFnWithoutVar(gq.Func) && len(gq.UID) > 0 { 763 if err := sg.populate(gq.UID); err != nil { 764 return nil, errors.Wrapf(err, "while populating UIDs") 765 } 766 } 767 768 // Copy roots filter. 769 if gq.Filter != nil { 770 sgf := &SubGraph{} 771 if err := filterCopy(sgf, gq.Filter); err != nil { 772 return nil, errors.Wrapf(err, "while copying filter") 773 } 774 sg.Filters = append(sg.Filters, sgf) 775 } 776 if gq.FacetsFilter != nil { 777 facetsFilter, err := toFacetsFilter(gq.FacetsFilter) 778 if err != nil { 779 return nil, errors.Wrapf(err, "while converting to facets filter") 780 } 781 sg.facetsFilter = facetsFilter 782 } 783 return sg, nil 784 } 785 786 func toFacetsFilter(gft *gql.FilterTree) (*pb.FilterTree, error) { 787 if gft == nil { 788 return nil, nil 789 } 790 if gft.Func != nil && len(gft.Func.NeedsVar) != 0 { 791 return nil, errors.Errorf("Variables not supported in pb.FilterTree") 792 } 793 ftree := &pb.FilterTree{Op: gft.Op} 794 for _, gftc := range gft.Child { 795 ftc, err := toFacetsFilter(gftc) 796 if err != nil { 797 return nil, err 798 } 799 ftree.Children = append(ftree.Children, ftc) 800 } 801 if gft.Func != nil { 802 ftree.Func = &pb.Function{ 803 Key: gft.Func.Attr, 804 Name: gft.Func.Name, 805 } 806 // TODO(Janardhan): Handle variable in facets later. 807 for _, arg := range gft.Func.Args { 808 ftree.Func.Args = append(ftree.Func.Args, arg.Value) 809 } 810 } 811 return ftree, nil 812 } 813 814 // createTaskQuery generates the query buffer. 815 func createTaskQuery(sg *SubGraph) (*pb.Query, error) { 816 attr := sg.Attr 817 // Might be safer than just checking first byte due to i18n 818 reverse := strings.HasPrefix(attr, "~") 819 if reverse { 820 attr = strings.TrimPrefix(attr, "~") 821 } 822 var srcFunc *pb.SrcFunction 823 if sg.SrcFunc != nil { 824 srcFunc = &pb.SrcFunction{} 825 srcFunc.Name = sg.SrcFunc.Name 826 srcFunc.IsCount = sg.SrcFunc.IsCount 827 for _, arg := range sg.SrcFunc.Args { 828 srcFunc.Args = append(srcFunc.Args, arg.Value) 829 if arg.IsValueVar { 830 return nil, errors.Errorf("Unsupported use of value var") 831 } 832 } 833 } 834 835 // If the lang is set to *, query all the languages. 836 if len(sg.Params.Langs) == 1 && sg.Params.Langs[0] == "*" { 837 sg.Params.expandAll = true 838 sg.Params.Langs = nil 839 } 840 841 out := &pb.Query{ 842 ReadTs: sg.ReadTs, 843 Cache: int32(sg.Cache), 844 Attr: attr, 845 Langs: sg.Params.Langs, 846 Reverse: reverse, 847 SrcFunc: srcFunc, 848 AfterUid: sg.Params.AfterUID, 849 DoCount: len(sg.Filters) == 0 && sg.Params.DoCount, 850 FacetParam: sg.Params.Facet, 851 FacetsFilter: sg.facetsFilter, 852 ExpandAll: sg.Params.expandAll, 853 } 854 855 if sg.SrcUIDs != nil { 856 out.UidList = sg.SrcUIDs 857 } 858 return out, nil 859 } 860 861 // varValue is a generic representation of a variable and holds multiple things. 862 // TODO(pawan) - Come back to this and document what do individual fields mean and when are they 863 // populated. 864 type varValue struct { 865 Uids *pb.List // list of uids if this denotes a uid variable. 866 Vals map[uint64]types.Val 867 path []*SubGraph // This stores the subgraph path from root to var definition. 868 // strList stores the valueMatrix corresponding to a predicate and is later used in 869 // expand(val(x)) query. 870 strList []*pb.ValueList 871 } 872 873 func evalLevelAgg( 874 doneVars map[string]varValue, 875 sg, parent *SubGraph) (map[uint64]types.Val, error) { 876 var mp map[uint64]types.Val 877 878 if parent == nil { 879 return nil, ErrWrongAgg 880 } 881 882 needsVar := sg.Params.NeedsVar[0].Name 883 if parent.Params.IsEmpty { 884 // The aggregated value doesn't really belong to a uid, we put it in uidToVal map 885 // corresponding to uid 0 to avoid defining another field in SubGraph. 886 vals := doneVars[needsVar].Vals 887 if len(vals) == 0 { 888 mp = make(map[uint64]types.Val) 889 mp[0] = types.Val{Tid: types.FloatID, Value: 0.0} 890 return mp, nil 891 } 892 893 ag := aggregator{ 894 name: sg.SrcFunc.Name, 895 } 896 for _, val := range vals { 897 ag.Apply(val) 898 } 899 v, err := ag.Value() 900 if err != nil && err != ErrEmptyVal { 901 return nil, err 902 } 903 if v.Value != nil { 904 mp = make(map[uint64]types.Val) 905 mp[0] = v 906 } 907 return mp, nil 908 } 909 910 var relSG *SubGraph 911 for _, ch := range parent.Children { 912 if sg == ch { 913 continue 914 } 915 for _, v := range ch.Params.FacetVar { 916 if v == needsVar { 917 relSG = ch 918 } 919 } 920 for _, cch := range ch.Children { 921 // Find the sibling node whose child has the required variable. 922 if cch.Params.Var == needsVar { 923 relSG = ch 924 } 925 } 926 } 927 if relSG == nil { 928 return nil, errors.Errorf("Invalid variable aggregation. Check the levels.") 929 } 930 931 vals := doneVars[needsVar].Vals 932 mp = make(map[uint64]types.Val) 933 // Go over the sibling node and aggregate. 934 for i, list := range relSG.uidMatrix { 935 ag := aggregator{ 936 name: sg.SrcFunc.Name, 937 } 938 for _, uid := range list.Uids { 939 if val, ok := vals[uid]; ok { 940 ag.Apply(val) 941 } 942 } 943 v, err := ag.Value() 944 if err != nil && err != ErrEmptyVal { 945 return nil, err 946 } 947 if v.Value != nil { 948 mp[relSG.SrcUIDs.Uids[i]] = v 949 } 950 } 951 return mp, nil 952 } 953 954 func (mt *mathTree) extractVarNodes() []*mathTree { 955 var nodeList []*mathTree 956 for _, ch := range mt.Child { 957 nodeList = append(nodeList, ch.extractVarNodes()...) 958 } 959 if mt.Var != "" { 960 nodeList = append(nodeList, mt) 961 return nodeList 962 } 963 return nodeList 964 } 965 966 // transformTo transforms fromNode to toNode level using the path between them and the 967 // corresponding uidMatrices. 968 func (fromNode *varValue) transformTo(toPath []*SubGraph) (map[uint64]types.Val, error) { 969 if len(toPath) < len(fromNode.path) { 970 return fromNode.Vals, nil 971 } 972 973 idx := 0 974 for ; idx < len(fromNode.path); idx++ { 975 if fromNode.path[idx] != toPath[idx] { 976 return fromNode.Vals, nil 977 } 978 } 979 980 if len(fromNode.Vals) == 0 { 981 return fromNode.Vals, nil 982 } 983 984 newMap := fromNode.Vals 985 for ; idx < len(toPath); idx++ { 986 curNode := toPath[idx] 987 tempMap := make(map[uint64]types.Val) 988 if idx == 0 { 989 continue 990 } 991 992 for i := 0; i < len(curNode.uidMatrix); i++ { 993 ul := curNode.uidMatrix[i] 994 srcUid := curNode.SrcUIDs.Uids[i] 995 curVal, ok := newMap[srcUid] 996 if !ok || curVal.Value == nil { 997 continue 998 } 999 if curVal.Tid != types.IntID && curVal.Tid != types.FloatID { 1000 return nil, errors.Errorf("Encountered non int/float type for summing") 1001 } 1002 for j := 0; j < len(ul.Uids); j++ { 1003 dstUid := ul.Uids[j] 1004 ag := aggregator{name: "sum"} 1005 ag.Apply(curVal) 1006 ag.Apply(tempMap[dstUid]) 1007 val, err := ag.Value() 1008 if err != nil { 1009 continue 1010 } 1011 tempMap[dstUid] = val 1012 } 1013 } 1014 newMap = tempMap 1015 } 1016 return newMap, nil 1017 } 1018 1019 // transformVars transforms all the variables to the variable at the lowest level 1020 func (sg *SubGraph) transformVars(doneVars map[string]varValue, path []*SubGraph) error { 1021 mNode := sg.MathExp 1022 mvarList := mNode.extractVarNodes() 1023 for i := 0; i < len(mvarList); i++ { 1024 mt := mvarList[i] 1025 curNode := doneVars[mt.Var] 1026 newMap, err := curNode.transformTo(path) 1027 if err != nil { 1028 return err 1029 } 1030 1031 // This is the result of setting the result of count(uid) to a variable. 1032 // Treat this value as a constant. 1033 if val, ok := newMap[math.MaxUint64]; ok && len(newMap) == 1 { 1034 mt.Const = val 1035 continue 1036 } 1037 1038 mt.Val = newMap 1039 } 1040 return nil 1041 } 1042 1043 func (sg *SubGraph) valueVarAggregation(doneVars map[string]varValue, path []*SubGraph, 1044 parent *SubGraph) error { 1045 if !sg.IsInternal() && !sg.IsGroupBy() && !sg.Params.IsEmpty { 1046 return nil 1047 } 1048 1049 // Aggregation function won't be present at root. 1050 if sg.Params.IsEmpty && parent == nil { 1051 return nil 1052 } 1053 1054 if sg.IsGroupBy() { 1055 if err := sg.processGroupBy(doneVars, path); err != nil { 1056 return err 1057 } 1058 } else if sg.SrcFunc != nil && !parent.IsGroupBy() && isAggregatorFn(sg.SrcFunc.Name) { 1059 // Aggregate the value over level. 1060 mp, err := evalLevelAgg(doneVars, sg, parent) 1061 if err != nil { 1062 return err 1063 } 1064 if sg.Params.Var != "" { 1065 it := doneVars[sg.Params.Var] 1066 it.Vals = mp 1067 doneVars[sg.Params.Var] = it 1068 } 1069 sg.Params.uidToVal = mp 1070 } else if sg.MathExp != nil { 1071 // Preprocess to bring all variables to the same level. 1072 err := sg.transformVars(doneVars, path) 1073 if err != nil { 1074 return err 1075 } 1076 1077 err = evalMathTree(sg.MathExp) 1078 if err != nil { 1079 return err 1080 } 1081 if len(sg.MathExp.Val) != 0 { 1082 it := doneVars[sg.Params.Var] 1083 var isInt, isFloat bool 1084 for _, v := range sg.MathExp.Val { 1085 if v.Tid == types.FloatID { 1086 isFloat = true 1087 } 1088 if v.Tid == types.IntID { 1089 isInt = true 1090 } 1091 } 1092 if isInt && isFloat { 1093 for k, v := range sg.MathExp.Val { 1094 if v.Tid == types.IntID { 1095 v.Tid = types.FloatID 1096 v.Value = float64(v.Value.(int64)) 1097 } 1098 sg.MathExp.Val[k] = v 1099 } 1100 } 1101 1102 it.Vals = sg.MathExp.Val 1103 // The path of math node is the path of max var node used in it. 1104 it.path = path 1105 doneVars[sg.Params.Var] = it 1106 sg.Params.uidToVal = sg.MathExp.Val 1107 } else if sg.MathExp.Const.Value != nil { 1108 // Assign the const for all the srcUids. 1109 mp := make(map[uint64]types.Val) 1110 rangeOver := sg.SrcUIDs 1111 if parent == nil { 1112 rangeOver = sg.DestUIDs 1113 } 1114 if rangeOver == nil { 1115 it := doneVars[sg.Params.Var] 1116 it.Vals = mp 1117 doneVars[sg.Params.Var] = it 1118 return nil 1119 } 1120 for _, uid := range rangeOver.Uids { 1121 mp[uid] = sg.MathExp.Const 1122 } 1123 it := doneVars[sg.Params.Var] 1124 it.Vals = mp 1125 doneVars[sg.Params.Var] = it 1126 sg.Params.uidToVal = mp 1127 } else { 1128 glog.V(3).Info("Warning: Math expression is using unassigned values or constants") 1129 } 1130 // Put it in this node. 1131 } else if len(sg.Params.NeedsVar) > 0 { 1132 // This is a var() block. 1133 srcVar := sg.Params.NeedsVar[0] 1134 srcMap := doneVars[srcVar.Name] 1135 // The value var can be empty. No need to check for nil. 1136 sg.Params.uidToVal = srcMap.Vals 1137 } else { 1138 return errors.Errorf("Unhandled pb.node %v with parent %v", sg.Attr, parent.Attr) 1139 } 1140 1141 return nil 1142 } 1143 1144 func (sg *SubGraph) populatePostAggregation(doneVars map[string]varValue, path []*SubGraph, 1145 parent *SubGraph) error { 1146 for idx := 0; idx < len(sg.Children); idx++ { 1147 child := sg.Children[idx] 1148 path = append(path, sg) 1149 err := child.populatePostAggregation(doneVars, path, sg) 1150 path = path[:len(path)-1] 1151 if err != nil { 1152 return err 1153 } 1154 } 1155 return sg.valueVarAggregation(doneVars, path, parent) 1156 } 1157 1158 // Filters might have updated the destuids. facetMatrix should also be updated to exclude uids that 1159 // were removed.. 1160 func (sg *SubGraph) updateFacetMatrix() { 1161 if len(sg.facetsMatrix) != len(sg.uidMatrix) { 1162 return 1163 } 1164 1165 for lidx, l := range sg.uidMatrix { 1166 out := sg.facetsMatrix[lidx].FacetsList[:0] 1167 for idx, uid := range l.Uids { 1168 // If uid wasn't filtered then we keep the facet for it. 1169 if algo.IndexOf(sg.DestUIDs, uid) >= 0 { 1170 out = append(out, sg.facetsMatrix[lidx].FacetsList[idx]) 1171 } 1172 } 1173 sg.facetsMatrix[lidx].FacetsList = out 1174 } 1175 } 1176 1177 // updateUidMatrix is used to filter out the uids in uidMatrix which are not part of DestUIDs 1178 // anymore. Some uids might have been removed from DestUids after application of filters, 1179 // we remove them from the uidMatrix as well. 1180 // If the query didn't specify sorting, we can just intersect the DestUids with lists in the 1181 // uidMatrix since they are both sorted. Otherwise we must filter out the uids within the 1182 // lists in uidMatrix which are not in DestUIDs. 1183 func (sg *SubGraph) updateUidMatrix() { 1184 sg.updateFacetMatrix() 1185 for _, l := range sg.uidMatrix { 1186 if len(sg.Params.Order) > 0 || len(sg.Params.FacetOrder) > 0 { 1187 // We can't do intersection directly as the list is not sorted by UIDs. 1188 // So do filter. 1189 algo.ApplyFilter(l, func(uid uint64, idx int) bool { 1190 return algo.IndexOf(sg.DestUIDs, uid) >= 0 // Binary search. 1191 }) 1192 } else { 1193 // If we didn't order on UIDmatrix, it'll be sorted. 1194 algo.IntersectWith(l, sg.DestUIDs, l) 1195 } 1196 } 1197 } 1198 1199 // populateVarMap stores the value of the variable defined in this SubGraph into req.Vars so that it 1200 // is available to other queries as well. It is called after a query has been executed. 1201 // TODO (pawan) - This function also transforms the DestUids and uidMatrix if the query is a cascade 1202 // query which should probably happen before. 1203 func (sg *SubGraph) populateVarMap(doneVars map[string]varValue, sgPath []*SubGraph) error { 1204 if sg.DestUIDs == nil || sg.IsGroupBy() { 1205 return nil 1206 } 1207 out := make([]uint64, 0, len(sg.DestUIDs.Uids)) 1208 if sg.Params.Alias == "shortest" { 1209 goto AssignStep 1210 } 1211 1212 if len(sg.Filters) > 0 { 1213 sg.updateUidMatrix() 1214 } 1215 1216 for _, child := range sg.Children { 1217 sgPath = append(sgPath, sg) // Add the current node to path 1218 if err := child.populateVarMap(doneVars, sgPath); err != nil { 1219 return err 1220 } 1221 sgPath = sgPath[:len(sgPath)-1] // Backtrack 1222 if !sg.Params.Cascade { 1223 continue 1224 } 1225 1226 // Intersect the UidMatrix with the DestUids as some UIDs might have been removed 1227 // by other operations. So we need to apply it on the UidMatrix. 1228 child.updateUidMatrix() 1229 } 1230 1231 if !sg.Params.Cascade { 1232 goto AssignStep 1233 } 1234 1235 // Filter out UIDs that don't have atleast one UID in every child. 1236 for i, uid := range sg.DestUIDs.Uids { 1237 var exclude bool 1238 for _, child := range sg.Children { 1239 // For uid we dont actually populate the uidMatrix or values. So a node asking for 1240 // uid would always be excluded. Therefore we skip it. 1241 if child.Attr == "uid" { 1242 continue 1243 } 1244 1245 // If the length of child UID list is zero and it has no valid value, then the 1246 // current UID should be removed from this level. 1247 if !child.IsInternal() && 1248 // Check len before accessing index. 1249 (len(child.valueMatrix) <= i || len(child.valueMatrix[i].Values) == 0) && 1250 (len(child.counts) <= i) && 1251 (len(child.uidMatrix) <= i || len(child.uidMatrix[i].Uids) == 0) { 1252 exclude = true 1253 break 1254 } 1255 } 1256 if !exclude { 1257 out = append(out, uid) 1258 } 1259 } 1260 // Note the we can't overwrite DestUids, as it'd also modify the SrcUids of 1261 // next level and the mapping from SrcUids to uidMatrix would be lost. 1262 sg.DestUIDs = &pb.List{Uids: out} 1263 1264 AssignStep: 1265 return sg.updateVars(doneVars, sgPath) 1266 } 1267 1268 // updateVars is used to update the doneVars map with the value of the variable from the SubGraph. 1269 // The variable could be a uid or a value variable. 1270 // It is called twice 1271 // 1. To populate sg.Params.ParentVars map with the value of a variable to pass down to children 1272 // subgraphs in a query. 1273 // 2. To populate req.Vars, which is used by other queries requiring variables.. 1274 func (sg *SubGraph) updateVars(doneVars map[string]varValue, sgPath []*SubGraph) error { 1275 // NOTE: although we initialize doneVars (req.Vars) in ProcessQuery, this nil check is for 1276 // non-root lookups that happen to other nodes. Don't use len(doneVars) == 0 ! 1277 if doneVars == nil || (sg.Params.Var == "" && sg.Params.FacetVar == nil) { 1278 return nil 1279 } 1280 1281 sgPathCopy := append(sgPath[:0:0], sgPath...) 1282 if err := sg.populateUidValVar(doneVars, sgPathCopy); err != nil { 1283 return err 1284 } 1285 return sg.populateFacetVars(doneVars, sgPathCopy) 1286 } 1287 1288 // populateUidValVar populates the value of the variable into doneVars. 1289 func (sg *SubGraph) populateUidValVar(doneVars map[string]varValue, sgPath []*SubGraph) error { 1290 if sg.Params.Var == "" { 1291 return nil 1292 } 1293 1294 var v varValue 1295 var ok bool 1296 // 1. When count of a predicate is assigned a variable, we store the mapping of uid => 1297 // count(predicate). 1298 if len(sg.counts) > 0 { 1299 // This implies it is a value variable. 1300 doneVars[sg.Params.Var] = varValue{ 1301 Vals: make(map[uint64]types.Val), 1302 path: sgPath, 1303 strList: sg.valueMatrix, 1304 } 1305 for idx, uid := range sg.SrcUIDs.Uids { 1306 val := types.Val{ 1307 Tid: types.IntID, 1308 Value: int64(sg.counts[idx]), 1309 } 1310 doneVars[sg.Params.Var].Vals[uid] = val 1311 } 1312 } else if sg.Params.uidCount { 1313 // 2. This is the case where count(uid) is requested in the query and stored as variable. 1314 // In this case there is just one value which is stored corresponding to the uid 1315 // math.MaxUint64 which isn't entirely correct as there could be an actual uid with that 1316 // value. 1317 doneVars[sg.Params.Var] = varValue{ 1318 Vals: make(map[uint64]types.Val), 1319 path: sgPath, 1320 strList: sg.valueMatrix, 1321 } 1322 1323 val := types.Val{ 1324 Tid: types.IntID, 1325 Value: int64(len(sg.DestUIDs.Uids)), 1326 } 1327 doneVars[sg.Params.Var].Vals[math.MaxUint64] = val 1328 } else if len(sg.DestUIDs.Uids) != 0 || (sg.Attr == "uid" && sg.SrcUIDs != nil) { 1329 // 3. A uid variable. The variable could be defined in one of two places. 1330 // a) Either on the actual predicate. 1331 // me(func: (...)) { 1332 // a as friend 1333 // } 1334 // 1335 // b) Or on the uid edge 1336 // me(func:(...)) { 1337 // friend { 1338 // a as uid 1339 // } 1340 // } 1341 1342 // Uid variable could be defined using uid or a predicate. 1343 uids := sg.DestUIDs 1344 if sg.Attr == "uid" { 1345 uids = sg.SrcUIDs 1346 } 1347 1348 if v, ok = doneVars[sg.Params.Var]; !ok { 1349 doneVars[sg.Params.Var] = varValue{ 1350 Uids: uids, 1351 path: sgPath, 1352 Vals: make(map[uint64]types.Val), 1353 strList: sg.valueMatrix, 1354 } 1355 return nil 1356 } 1357 1358 // For a recurse query this can happen. We don't allow using the same variable more than 1359 // once otherwise. 1360 lists := append([]*pb.List(nil), v.Uids, uids) 1361 v.Uids = algo.MergeSorted(lists) 1362 doneVars[sg.Params.Var] = v 1363 } else if len(sg.valueMatrix) != 0 && sg.SrcUIDs != nil && len(sgPath) != 0 { 1364 // 4. A value variable. We get the first value from every list thats part of ValueMatrix 1365 // and store it corresponding to a uid in SrcUIDs. 1366 if v, ok = doneVars[sg.Params.Var]; !ok { 1367 v.Vals = make(map[uint64]types.Val) 1368 v.path = sgPath 1369 v.strList = sg.valueMatrix 1370 } 1371 1372 for idx, uid := range sg.SrcUIDs.Uids { 1373 if len(sg.valueMatrix[idx].Values) > 1 { 1374 return errors.Errorf("Value variables not supported for predicate with list type.") 1375 } 1376 1377 if len(sg.valueMatrix[idx].Values) == 0 { 1378 continue 1379 } 1380 val, err := convertWithBestEffort(sg.valueMatrix[idx].Values[0], sg.Attr) 1381 if err != nil { 1382 continue 1383 } 1384 v.Vals[uid] = val 1385 } 1386 doneVars[sg.Params.Var] = v 1387 } else { 1388 // If the variable already existed and now we see it again without any DestUIDs or 1389 // ValueMatrix then lets just return. 1390 if _, ok := doneVars[sg.Params.Var]; ok { 1391 return nil 1392 } 1393 // Insert a empty entry to keep the dependency happy. 1394 doneVars[sg.Params.Var] = varValue{ 1395 path: sgPath, 1396 Vals: make(map[uint64]types.Val), 1397 strList: sg.valueMatrix, 1398 } 1399 } 1400 return nil 1401 } 1402 1403 // populateFacetVars walks the facetsMatrix to compute the value of a facet variable. 1404 // It sums up the value for float/int type facets so that there is only variable corresponding 1405 // to each uid in the uidMatrix. 1406 func (sg *SubGraph) populateFacetVars(doneVars map[string]varValue, sgPath []*SubGraph) error { 1407 if len(sg.Params.FacetVar) == 0 || sg.Params.Facet == nil { 1408 return nil 1409 } 1410 1411 sgPath = append(sgPath, sg) 1412 for _, it := range sg.Params.Facet.Param { 1413 fvar, ok := sg.Params.FacetVar[it.Key] 1414 if !ok { 1415 continue 1416 } 1417 // Assign an empty value for every facet that was assigned to a variable and hence is part 1418 // of FacetVar. 1419 doneVars[fvar] = varValue{ 1420 Vals: make(map[uint64]types.Val), 1421 path: sgPath, 1422 } 1423 } 1424 1425 if len(sg.facetsMatrix) == 0 { 1426 return nil 1427 } 1428 1429 // Note: We ignore the facets if its a value edge as we can't 1430 // attach the value to any node. 1431 for i, uids := range sg.uidMatrix { 1432 for j, uid := range uids.Uids { 1433 facet := sg.facetsMatrix[i].FacetsList[j] 1434 for _, f := range facet.Facets { 1435 fvar, ok := sg.Params.FacetVar[f.Key] 1436 if !ok { 1437 continue 1438 } 1439 if pVal, ok := doneVars[fvar].Vals[uid]; !ok { 1440 fVal, err := facets.ValFor(f) 1441 if err != nil { 1442 return err 1443 } 1444 1445 doneVars[fvar].Vals[uid] = fVal 1446 } else { 1447 // If the value is int/float we add them up. Else we throw an error as 1448 // many to one maps are not allowed for other types. 1449 nVal, err := facets.ValFor(f) 1450 if err != nil { 1451 return err 1452 } 1453 1454 if nVal.Tid != types.IntID && nVal.Tid != types.FloatID { 1455 return errors.Errorf("Repeated id with non int/float value for " + 1456 "facet var encountered.") 1457 } 1458 ag := aggregator{name: "sum"} 1459 ag.Apply(pVal) 1460 ag.Apply(nVal) 1461 fVal, err := ag.Value() 1462 if err != nil { 1463 continue 1464 } 1465 doneVars[fvar].Vals[uid] = fVal 1466 } 1467 } 1468 } 1469 } 1470 return nil 1471 } 1472 1473 // recursiveFillVars fills the value of variables before a query is to be processed using the result 1474 // of the values (doneVars) computed by other queries that were successfully run before this query. 1475 func (sg *SubGraph) recursiveFillVars(doneVars map[string]varValue) error { 1476 err := sg.fillVars(doneVars) 1477 if err != nil { 1478 return err 1479 } 1480 for _, child := range sg.Children { 1481 err = child.recursiveFillVars(doneVars) 1482 if err != nil { 1483 return err 1484 } 1485 } 1486 for _, fchild := range sg.Filters { 1487 err = fchild.recursiveFillVars(doneVars) 1488 if err != nil { 1489 return err 1490 } 1491 } 1492 return nil 1493 } 1494 1495 // fillShortestPathVars reads value of the uid variable from mp map and fills it into From and To 1496 // parameters. 1497 func (sg *SubGraph) fillShortestPathVars(mp map[string]varValue) error { 1498 // The uidVar.Uids can be nil if the variable didn't return any uids. This would mean 1499 // sg.Params.From or sg.Params.To is 0 and the query would return an empty result. 1500 if sg.Params.ShortestPathArgs.From != nil && len(sg.Params.ShortestPathArgs.From.NeedsVar) > 0 { 1501 fromVar := sg.Params.ShortestPathArgs.From.NeedsVar[0].Name 1502 uidVar, ok := mp[fromVar] 1503 if !ok { 1504 return errors.Errorf("value of from var(%s) should have already been populated", 1505 fromVar) 1506 } 1507 if uidVar.Uids != nil { 1508 if len(uidVar.Uids.Uids) > 1 { 1509 return errors.Errorf("from variable(%s) should only expand to 1 uid", fromVar) 1510 } 1511 sg.Params.From = uidVar.Uids.Uids[0] 1512 } 1513 } 1514 1515 if sg.Params.ShortestPathArgs.To != nil && len(sg.Params.ShortestPathArgs.To.NeedsVar) > 0 { 1516 toVar := sg.Params.ShortestPathArgs.To.NeedsVar[0].Name 1517 uidVar, ok := mp[toVar] 1518 if !ok { 1519 return errors.Errorf("value of to var(%s) should have already been populated", 1520 toVar) 1521 } 1522 if uidVar.Uids != nil { 1523 if len(uidVar.Uids.Uids) > 1 { 1524 return errors.Errorf("to variable(%s) should only expand to 1 uid", toVar) 1525 } 1526 sg.Params.To = uidVar.Uids.Uids[0] 1527 } 1528 } 1529 return nil 1530 } 1531 1532 // fillVars reads the value corresponding to a variable from the map mp and stores it inside 1533 // SubGraph. This value is then later used for execution of the SubGraph. 1534 func (sg *SubGraph) fillVars(mp map[string]varValue) error { 1535 if sg.Params.Alias == "shortest" { 1536 if err := sg.fillShortestPathVars(mp); err != nil { 1537 return err 1538 } 1539 } 1540 1541 var lists []*pb.List 1542 // Go through all the variables in NeedsVar and see if we have a value for them in the map. If 1543 // we do, then we store that value in the appropriate variable inside SubGraph. 1544 for _, v := range sg.Params.NeedsVar { 1545 l, ok := mp[v.Name] 1546 if !ok { 1547 continue 1548 } 1549 switch { 1550 case (v.Typ == gql.AnyVar || v.Typ == gql.ListVar) && l.strList != nil: 1551 // This is for the case when we use expand(val(x)) with a value variable. 1552 // We populate the list of values into ExpandPreds and use that for the expand query 1553 // later. 1554 // TODO: If we support value vars for list type then this needn't be true 1555 sg.ExpandPreds = l.strList 1556 1557 case (v.Typ == gql.AnyVar || v.Typ == gql.UidVar) && l.Uids != nil: 1558 lists = append(lists, l.Uids) 1559 1560 case (v.Typ == gql.AnyVar || v.Typ == gql.ValueVar): 1561 // This should happen only once. 1562 // TODO: This allows only one value var per subgraph, change it later 1563 sg.Params.uidToVal = l.Vals 1564 1565 case (v.Typ == gql.AnyVar || v.Typ == gql.UidVar) && len(l.Vals) != 0: 1566 // Derive the UID list from value var. 1567 uids := make([]uint64, 0, len(l.Vals)) 1568 for k := range l.Vals { 1569 uids = append(uids, k) 1570 } 1571 sort.Slice(uids, func(i, j int) bool { return uids[i] < uids[j] }) 1572 lists = append(lists, &pb.List{Uids: uids}) 1573 1574 case len(l.Vals) != 0 || l.Uids != nil: 1575 return errors.Errorf("Wrong variable type encountered for var(%v) %v.", v.Name, v.Typ) 1576 1577 default: 1578 glog.V(3).Infof("Warning: reached default case in fillVars for var: %v", v.Name) 1579 } 1580 } 1581 if err := sg.replaceVarInFunc(); err != nil { 1582 return err 1583 } 1584 lists = append(lists, sg.DestUIDs) 1585 sg.DestUIDs = algo.MergeSorted(lists) 1586 return nil 1587 } 1588 1589 // replaceVarInFunc gets values stored inside uidToVal(coming from a value variable defined in some 1590 // other query) and adds them as arguments to the SrcFunc in SubGraph. 1591 // E.g. - func: eq(score, val(myscore)) 1592 // NOTE - We disallow vars in facets filter so we don't need to worry about that as of now. 1593 func (sg *SubGraph) replaceVarInFunc() error { 1594 if sg.SrcFunc == nil { 1595 return nil 1596 } 1597 var args []gql.Arg 1598 // Iterate over the args and replace value args with their values 1599 for _, arg := range sg.SrcFunc.Args { 1600 if !arg.IsValueVar { 1601 args = append(args, arg) 1602 continue 1603 } 1604 if len(sg.Params.uidToVal) == 0 { 1605 // This means that the variable didn't have any values and hence there is nothing to add 1606 // to args. 1607 break 1608 } 1609 // We don't care about uids, just take all the values and put as args. 1610 // There would be only one value var per subgraph as per current assumptions. 1611 seenArgs := make(map[string]struct{}) 1612 for _, v := range sg.Params.uidToVal { 1613 data := types.ValueForType(types.StringID) 1614 if err := types.Marshal(v, &data); err != nil { 1615 return err 1616 } 1617 val := data.Value.(string) 1618 if _, ok := seenArgs[val]; ok { 1619 continue 1620 } 1621 seenArgs[val] = struct{}{} 1622 args = append(args, gql.Arg{Value: val}) 1623 } 1624 } 1625 sg.SrcFunc.Args = args 1626 return nil 1627 } 1628 1629 // Used to evaluate an inequality function which uses a value variable instead of a predicate. 1630 // E.g. 1631 // 1. func: eq(val(x), 35) or @filter(eq(val(x), 35) 1632 // 2. func: ge(val(x), 40) or @filter(ge(val(x), 40) 1633 // ... other inequality functions 1634 // The function filters uids corresponding to the variable which satisfy the inequality and stores 1635 // the filtered uids in DestUIDs. 1636 func (sg *SubGraph) applyIneqFunc() error { 1637 if len(sg.Params.uidToVal) == 0 { 1638 // Expected a valid value map. But got empty. 1639 // Don't return error, return empty - issue #2610 1640 return nil 1641 } 1642 1643 // A mapping of uid to their value should have already been stored in uidToVal. 1644 // Find out the type of value using the first value in the map and try to convert the function 1645 // argument to that type to make sure we can compare them. If we can't return an error. 1646 var typ types.TypeID 1647 for _, v := range sg.Params.uidToVal { 1648 typ = v.Tid 1649 break 1650 } 1651 val := sg.SrcFunc.Args[0].Value 1652 src := types.Val{Tid: types.StringID, Value: []byte(val)} 1653 dst, err := types.Convert(src, typ) 1654 if err != nil { 1655 return errors.Errorf("Invalid argment %v. Comparing with different type", val) 1656 } 1657 1658 if sg.SrcUIDs != nil { 1659 // This means its a filter. 1660 for _, uid := range sg.SrcUIDs.Uids { 1661 curVal, ok := sg.Params.uidToVal[uid] 1662 if ok && types.CompareVals(sg.SrcFunc.Name, curVal, dst) { 1663 sg.DestUIDs.Uids = append(sg.DestUIDs.Uids, uid) 1664 } 1665 } 1666 } else { 1667 // This means it's a function at root as SrcUIDs is nil 1668 for uid, curVal := range sg.Params.uidToVal { 1669 if types.CompareVals(sg.SrcFunc.Name, curVal, dst) { 1670 sg.DestUIDs.Uids = append(sg.DestUIDs.Uids, uid) 1671 } 1672 } 1673 sort.Slice(sg.DestUIDs.Uids, func(i, j int) bool { 1674 return sg.DestUIDs.Uids[i] < sg.DestUIDs.Uids[j] 1675 }) 1676 sg.uidMatrix = []*pb.List{sg.DestUIDs} 1677 } 1678 return nil 1679 } 1680 1681 func (sg *SubGraph) appendDummyValues() { 1682 if sg.SrcUIDs == nil || len(sg.SrcUIDs.Uids) == 0 { 1683 return 1684 } 1685 var l pb.List 1686 var val pb.ValueList 1687 for range sg.SrcUIDs.Uids { 1688 // This is necessary so that preTraverse can be processed smoothly. 1689 sg.uidMatrix = append(sg.uidMatrix, &l) 1690 sg.valueMatrix = append(sg.valueMatrix, &val) 1691 } 1692 } 1693 1694 func getPredsFromVals(vl []*pb.ValueList) []string { 1695 preds := make([]string, 0) 1696 for _, l := range vl { 1697 for _, v := range l.Values { 1698 if len(v.Val) > 0 { 1699 preds = append(preds, string(v.Val)) 1700 } 1701 } 1702 } 1703 return preds 1704 } 1705 1706 func uniquePreds(list []string) []string { 1707 predMap := make(map[string]struct{}) 1708 for _, item := range list { 1709 predMap[item] = struct{}{} 1710 } 1711 1712 preds := make([]string, 0, len(predMap)) 1713 for pred := range predMap { 1714 preds = append(preds, pred) 1715 } 1716 return preds 1717 } 1718 1719 func recursiveCopy(dst *SubGraph, src *SubGraph) { 1720 dst.Attr = src.Attr 1721 dst.Params = src.Params 1722 dst.Params.ParentVars = make(map[string]varValue) 1723 for k, v := range src.Params.ParentVars { 1724 dst.Params.ParentVars[k] = v 1725 } 1726 1727 dst.copyFiltersRecurse(src) 1728 dst.ReadTs = src.ReadTs 1729 1730 for _, c := range src.Children { 1731 copyChild := new(SubGraph) 1732 recursiveCopy(copyChild, c) 1733 dst.Children = append(dst.Children, copyChild) 1734 } 1735 } 1736 1737 func expandSubgraph(ctx context.Context, sg *SubGraph) ([]*SubGraph, error) { 1738 span := otrace.FromContext(ctx) 1739 stop := x.SpanTimer(span, "expandSubgraph: "+sg.Attr) 1740 defer stop() 1741 1742 out := make([]*SubGraph, 0, len(sg.Children)) 1743 for i := 0; i < len(sg.Children); i++ { 1744 child := sg.Children[i] 1745 1746 if child.Params.Expand == "" { 1747 out = append(out, child) 1748 continue 1749 } 1750 1751 var preds []string 1752 types, err := getNodeTypes(ctx, sg) 1753 if err != nil { 1754 return out, err 1755 } 1756 1757 switch child.Params.Expand { 1758 // It could be expand(_all_), expand(_forward_), expand(_reverse_) or expand(val(x)). 1759 case "_all_": 1760 span.Annotate(nil, "expand(_all_)") 1761 if len(types) == 0 { 1762 break 1763 } 1764 1765 preds = getPredicatesFromTypes(types) 1766 rpreds, err := getReversePredicates(ctx, preds) 1767 if err != nil { 1768 return out, err 1769 } 1770 preds = append(preds, rpreds...) 1771 case "_forward_": 1772 span.Annotate(nil, "expand(_forward_)") 1773 if len(types) == 0 { 1774 break 1775 } 1776 1777 preds = getPredicatesFromTypes(types) 1778 case "_reverse_": 1779 span.Annotate(nil, "expand(_reverse_)") 1780 if len(types) == 0 { 1781 break 1782 } 1783 1784 typePreds := getPredicatesFromTypes(types) 1785 rpreds, err := getReversePredicates(ctx, typePreds) 1786 if err != nil { 1787 return out, err 1788 } 1789 preds = append(preds, rpreds...) 1790 default: 1791 span.Annotate(nil, "expand default") 1792 // We already have the predicates populated from the var. 1793 preds = getPredsFromVals(child.ExpandPreds) 1794 } 1795 preds = uniquePreds(preds) 1796 1797 for _, pred := range preds { 1798 temp := &SubGraph{ 1799 ReadTs: sg.ReadTs, 1800 Attr: pred, 1801 } 1802 temp.Params = child.Params 1803 temp.Params.expandAll = child.Params.Expand == "_all_" 1804 temp.Params.ParentVars = make(map[string]varValue) 1805 for k, v := range child.Params.ParentVars { 1806 temp.Params.ParentVars[k] = v 1807 } 1808 temp.Params.isInternal = false 1809 temp.Params.Expand = "" 1810 temp.Params.Facet = &pb.FacetParams{AllKeys: true} 1811 1812 // Go through each child, create a copy and attach to temp.Children. 1813 for _, cc := range child.Children { 1814 s := &SubGraph{} 1815 recursiveCopy(s, cc) 1816 temp.Children = append(temp.Children, s) 1817 } 1818 1819 for _, ch := range sg.Children { 1820 if ch.isSimilar(temp) { 1821 return out, errors.Errorf("Repeated subgraph: [%s] while using expand()", 1822 ch.Attr) 1823 } 1824 } 1825 out = append(out, temp) 1826 } 1827 } 1828 return out, nil 1829 } 1830 1831 // ProcessGraph processes the SubGraph instance accumulating result for the query 1832 // from different instances. Note: taskQuery is nil for root node. 1833 func ProcessGraph(ctx context.Context, sg, parent *SubGraph, rch chan error) { 1834 var suffix string 1835 if len(sg.Params.Alias) > 0 { 1836 suffix += "." + sg.Params.Alias 1837 } 1838 if len(sg.Attr) > 0 { 1839 suffix += "." + sg.Attr 1840 } 1841 span := otrace.FromContext(ctx) 1842 stop := x.SpanTimer(span, "query.ProcessGraph"+suffix) 1843 defer stop() 1844 1845 if sg.Attr == "uid" { 1846 // We dont need to call ProcessGraph for uid, as we already have uids 1847 // populated from parent and there is nothing to process but uidMatrix 1848 // and values need to have the right sizes so that preTraverse works. 1849 sg.appendDummyValues() 1850 rch <- nil 1851 return 1852 } 1853 var err error 1854 if parent == nil && sg.SrcFunc != nil && sg.SrcFunc.Name == "uid" { 1855 // I'm root and I'm using some variable that has been populated. 1856 // Retain the actual order in uidMatrix. But sort the destUids. 1857 if sg.SrcUIDs != nil && len(sg.SrcUIDs.Uids) != 0 { 1858 // I am root. I don't have any function to execute, and my 1859 // result has been prepared for me already by list passed by the user. 1860 // uidmatrix retains the order. SrcUids are sorted (in newGraph). 1861 sg.DestUIDs = sg.SrcUIDs 1862 } else { 1863 // Populated variable. 1864 o := append(sg.DestUIDs.Uids[:0:0], sg.DestUIDs.Uids...) 1865 sg.uidMatrix = []*pb.List{{Uids: o}} 1866 sort.Slice(sg.DestUIDs.Uids, func(i, j int) bool { 1867 return sg.DestUIDs.Uids[i] < sg.DestUIDs.Uids[j] 1868 }) 1869 } 1870 } else if len(sg.Attr) == 0 { 1871 // This is when we have uid function in children. 1872 if sg.SrcFunc != nil && sg.SrcFunc.Name == "uid" { 1873 // If its a uid() filter, we just have to intersect the SrcUIDs with DestUIDs 1874 // and return. 1875 if err := sg.fillVars(sg.Params.ParentVars); err != nil { 1876 rch <- err 1877 return 1878 } 1879 algo.IntersectWith(sg.DestUIDs, sg.SrcUIDs, sg.DestUIDs) 1880 rch <- nil 1881 return 1882 } 1883 1884 if sg.SrcUIDs == nil { 1885 glog.Errorf("SrcUIDs is unexpectedly nil. Subgraph: %+v", sg) 1886 rch <- errors.Errorf("SrcUIDs shouldn't be nil.") 1887 return 1888 } 1889 // If we have a filter SubGraph which only contains an operator, 1890 // it won't have any attribute to work on. 1891 // This is to allow providing SrcUIDs to the filter children. 1892 // Each filter use it's own (shallow) copy of SrcUIDs, so there is no race conditions, 1893 // when multiple filters replace their sg.DestUIDs 1894 sg.DestUIDs = &pb.List{Uids: sg.SrcUIDs.Uids} 1895 } else { 1896 isInequalityFn := sg.SrcFunc != nil && isInequalityFn(sg.SrcFunc.Name) 1897 if isInequalityFn && sg.SrcFunc.IsValueVar { 1898 // This is a ineq function which uses a value variable. 1899 err = sg.applyIneqFunc() 1900 if parent != nil { 1901 rch <- err 1902 return 1903 } 1904 } else if isInequalityFn && sg.SrcFunc.IsLenVar { 1905 // Safe to access 0th element here because if no variable was given, parser would throw 1906 // an error. 1907 val := sg.SrcFunc.Args[0].Value 1908 src := types.Val{Tid: types.StringID, Value: []byte(val)} 1909 dst, err := types.Convert(src, types.IntID) 1910 if err != nil { 1911 // TODO(Aman): needs to do parent check? 1912 rch <- errors.Wrapf(err, "invalid argument %v. Comparing with different type", val) 1913 return 1914 } 1915 1916 curVal := types.Val{Tid: types.IntID, Value: int64(len(sg.DestUIDs.Uids))} 1917 if types.CompareVals(sg.SrcFunc.Name, curVal, dst) { 1918 sg.DestUIDs.Uids = sg.SrcUIDs.Uids 1919 } else { 1920 sg.DestUIDs.Uids = nil 1921 } 1922 } else { 1923 taskQuery, err := createTaskQuery(sg) 1924 if err != nil { 1925 rch <- err 1926 return 1927 } 1928 result, err := worker.ProcessTaskOverNetwork(ctx, taskQuery) 1929 if err != nil && strings.Contains(err.Error(), worker.ErrNonExistentTabletMessage) { 1930 sg.UnknownAttr = true 1931 } else if err != nil { 1932 rch <- err 1933 return 1934 } 1935 1936 sg.uidMatrix = result.UidMatrix 1937 sg.valueMatrix = result.ValueMatrix 1938 sg.facetsMatrix = result.FacetMatrix 1939 sg.counts = result.Counts 1940 sg.LangTags = result.LangMatrix 1941 sg.List = result.List 1942 1943 if sg.Params.DoCount { 1944 if len(sg.Filters) == 0 { 1945 // If there is a filter, we need to do more work to get the actual count. 1946 rch <- nil 1947 return 1948 } 1949 sg.counts = make([]uint32, len(sg.uidMatrix)) 1950 } 1951 1952 if result.IntersectDest { 1953 sg.DestUIDs = algo.IntersectSorted(result.UidMatrix) 1954 } else { 1955 sg.DestUIDs = algo.MergeSorted(result.UidMatrix) 1956 } 1957 1958 if parent == nil { 1959 // I'm root. We reach here if root had a function. 1960 sg.uidMatrix = []*pb.List{sg.DestUIDs} 1961 } 1962 } 1963 } 1964 1965 // Run filters if any. 1966 if len(sg.Filters) > 0 { 1967 // Run all filters in parallel. 1968 filterChan := make(chan error, len(sg.Filters)) 1969 for _, filter := range sg.Filters { 1970 isUidFuncWithoutVar := filter.SrcFunc != nil && filter.SrcFunc.Name == "uid" && 1971 len(filter.Params.NeedsVar) == 0 1972 // For uid function filter, no need for processing. User already gave us the 1973 // list. Lets just update DestUIDs. 1974 if isUidFuncWithoutVar { 1975 filter.DestUIDs = filter.SrcUIDs 1976 filterChan <- nil 1977 continue 1978 } 1979 1980 filter.SrcUIDs = sg.DestUIDs 1981 // Passing the pointer is okay since the filter only reads. 1982 filter.Params.ParentVars = sg.Params.ParentVars // Pass to the child. 1983 go ProcessGraph(ctx, filter, sg, filterChan) 1984 } 1985 1986 var filterErr error 1987 for range sg.Filters { 1988 if err = <-filterChan; err != nil { 1989 // Store error in a variable and wait for all filters to run 1990 // before returning. Else tracing causes crashes. 1991 filterErr = err 1992 } 1993 } 1994 1995 if filterErr != nil { 1996 rch <- filterErr 1997 return 1998 } 1999 2000 // Now apply the results from filter. 2001 var lists []*pb.List 2002 for _, filter := range sg.Filters { 2003 lists = append(lists, filter.DestUIDs) 2004 } 2005 if sg.FilterOp == "or" { 2006 sg.DestUIDs = algo.MergeSorted(lists) 2007 } else if sg.FilterOp == "not" { 2008 x.AssertTrue(len(sg.Filters) == 1) 2009 sg.DestUIDs = algo.Difference(sg.DestUIDs, sg.Filters[0].DestUIDs) 2010 } else if sg.FilterOp == "and" { 2011 sg.DestUIDs = algo.IntersectSorted(lists) 2012 } else { 2013 // We need to also intersect the original dest uids in this case to get the final 2014 // DestUIDs. 2015 // me(func: eq(key, "key1")) @filter(eq(key, "key2")) 2016 2017 // TODO - See if the server performing the filter can intersect with the srcUIDs before 2018 // returning them in this case. 2019 lists = append(lists, sg.DestUIDs) 2020 sg.DestUIDs = algo.IntersectSorted(lists) 2021 } 2022 } 2023 2024 if len(sg.Params.Order) == 0 && len(sg.Params.FacetOrder) == 0 { 2025 // There is no ordering. Just apply pagination and return. 2026 if err = sg.applyPagination(ctx); err != nil { 2027 rch <- err 2028 return 2029 } 2030 } else { 2031 // If we are asked for count, we don't need to change the order of results. 2032 if !sg.Params.DoCount { 2033 // We need to sort first before pagination. 2034 if err = sg.applyOrderAndPagination(ctx); err != nil { 2035 rch <- err 2036 return 2037 } 2038 } 2039 } 2040 2041 // Here we consider handling count with filtering. We do this after 2042 // pagination because otherwise, we need to do the count with pagination 2043 // taken into account. For example, a PL might have only 50 entries but the 2044 // user wants to skip 100 entries and return 10 entries. In this case, you 2045 // should return a count of 0, not 10. 2046 // take care of the order 2047 if sg.Params.DoCount { 2048 x.AssertTrue(len(sg.Filters) > 0) 2049 sg.counts = make([]uint32, len(sg.uidMatrix)) 2050 sg.updateUidMatrix() 2051 for i, ul := range sg.uidMatrix { 2052 // A possible optimization is to return the size of the intersection 2053 // without forming the intersection. 2054 sg.counts[i] = uint32(len(ul.Uids)) 2055 } 2056 rch <- nil 2057 return 2058 } 2059 2060 if sg.Children, err = expandSubgraph(ctx, sg); err != nil { 2061 rch <- err 2062 return 2063 } 2064 2065 if sg.IsGroupBy() { 2066 // Add the attrs required by groupby nodes 2067 for _, it := range sg.Params.groupbyAttrs { 2068 // TODO - Throw error if Attr is of list type. 2069 sg.Children = append(sg.Children, &SubGraph{ 2070 Attr: it.Attr, 2071 ReadTs: sg.ReadTs, 2072 Params: params{ 2073 Alias: it.Alias, 2074 ignoreResult: true, 2075 Langs: it.Langs, 2076 }, 2077 }) 2078 } 2079 } 2080 2081 if len(sg.Children) > 0 { 2082 // We store any variable defined by this node in the map and pass it on 2083 // to the children which might depend on it. We only need to do this if the SubGraph 2084 // has children. 2085 if err = sg.updateVars(sg.Params.ParentVars, []*SubGraph{}); err != nil { 2086 rch <- err 2087 return 2088 } 2089 } 2090 2091 childChan := make(chan error, len(sg.Children)) 2092 for i := 0; i < len(sg.Children); i++ { 2093 child := sg.Children[i] 2094 child.Params.ParentVars = make(map[string]varValue) 2095 for k, v := range sg.Params.ParentVars { 2096 child.Params.ParentVars[k] = v 2097 } 2098 2099 child.SrcUIDs = sg.DestUIDs // Make the connection. 2100 if child.IsInternal() { 2101 // We dont have to execute these nodes. 2102 continue 2103 } 2104 go ProcessGraph(ctx, child, sg, childChan) 2105 } 2106 2107 var childErr error 2108 // Now get all the results back. 2109 for _, child := range sg.Children { 2110 if child.IsInternal() { 2111 continue 2112 } 2113 if err = <-childChan; err != nil { 2114 childErr = err 2115 } 2116 } 2117 2118 if sg.DestUIDs == nil || len(sg.DestUIDs.Uids) == 0 { 2119 // Looks like we're done here. Be careful with nil srcUIDs! 2120 if span != nil { 2121 span.Annotatef(nil, "Zero uids for %q", sg.Attr) 2122 } 2123 out := sg.Children[:0] 2124 for _, child := range sg.Children { 2125 if child.IsInternal() && child.Attr == "expand" { 2126 continue 2127 } 2128 out = append(out, child) 2129 } 2130 sg.Children = out // Remove any expand nodes we might have added. 2131 rch <- nil 2132 return 2133 } 2134 2135 rch <- childErr 2136 } 2137 2138 // applyPagination applies count and offset to lists inside uidMatrix. 2139 func (sg *SubGraph) applyPagination(ctx context.Context) error { 2140 if sg.Params.Count == 0 && sg.Params.Offset == 0 { // No pagination. 2141 return nil 2142 } 2143 2144 sg.updateUidMatrix() 2145 for i := 0; i < len(sg.uidMatrix); i++ { 2146 // Apply the offsets. 2147 start, end := x.PageRange(sg.Params.Count, sg.Params.Offset, len(sg.uidMatrix[i].Uids)) 2148 sg.uidMatrix[i].Uids = sg.uidMatrix[i].Uids[start:end] 2149 } 2150 // Re-merge the UID matrix. 2151 sg.DestUIDs = algo.MergeSorted(sg.uidMatrix) 2152 return nil 2153 } 2154 2155 // applyOrderAndPagination orders each posting list by a given attribute 2156 // before applying pagination. 2157 func (sg *SubGraph) applyOrderAndPagination(ctx context.Context) error { 2158 if len(sg.Params.Order) == 0 && len(sg.Params.FacetOrder) == 0 { 2159 return nil 2160 } 2161 2162 sg.updateUidMatrix() 2163 2164 // See if we need to apply order based on facet. 2165 if len(sg.Params.FacetOrder) != 0 { 2166 return sg.sortAndPaginateUsingFacet(ctx) 2167 } 2168 2169 for _, it := range sg.Params.NeedsVar { 2170 // TODO(pawan) - Return error if user uses var order with predicates. 2171 if len(sg.Params.Order) > 0 && it.Name == sg.Params.Order[0].Attr && 2172 (it.Typ == gql.ValueVar) { 2173 // If the Order name is same as var name and it's a value variable, we sort using that variable. 2174 return sg.sortAndPaginateUsingVar(ctx) 2175 } 2176 } 2177 2178 if sg.Params.Count == 0 { 2179 // Only retrieve up to 1000 results by default. 2180 sg.Params.Count = 1000 2181 } 2182 2183 x.AssertTrue(len(sg.Params.Order) > 0) 2184 2185 sort := &pb.SortMessage{ 2186 Order: sg.Params.Order, 2187 UidMatrix: sg.uidMatrix, 2188 Offset: int32(sg.Params.Offset), 2189 Count: int32(sg.Params.Count), 2190 ReadTs: sg.ReadTs, 2191 } 2192 result, err := worker.SortOverNetwork(ctx, sort) 2193 if err != nil { 2194 return err 2195 } 2196 2197 x.AssertTrue(len(result.UidMatrix) == len(sg.uidMatrix)) 2198 if sg.facetsMatrix != nil { 2199 // The order of uids in the lists which are part of the uidMatrix would have been changed 2200 // after sort. We want to update the order of lists in the facetMatrix accordingly. 2201 for idx, rl := range result.UidMatrix { 2202 fl := make([]*pb.Facets, 0, len(sg.facetsMatrix[idx].FacetsList)) 2203 for _, uid := range rl.Uids { 2204 // Find index of this uid in original sorted uid list. 2205 oidx := algo.IndexOf(sg.uidMatrix[idx], uid) 2206 // Find corresponding facet. 2207 fl = append(fl, sg.facetsMatrix[idx].FacetsList[oidx]) 2208 } 2209 sg.facetsMatrix[idx].FacetsList = fl 2210 } 2211 } 2212 2213 sg.uidMatrix = result.UidMatrix 2214 // Update the destUids as we might have removed some UIDs for which we didn't find any values 2215 // while sorting. 2216 sg.updateDestUids() 2217 return nil 2218 } 2219 2220 func (sg *SubGraph) updateDestUids() { 2221 // Update sg.destUID. Iterate over the UID matrix (which is not sorted by 2222 // UID). For each element in UID matrix, we do a binary search in the 2223 // current destUID and mark it. Then we scan over this bool array and 2224 // rebuild destUIDs. 2225 included := make([]bool, len(sg.DestUIDs.Uids)) 2226 for _, ul := range sg.uidMatrix { 2227 for _, uid := range ul.Uids { 2228 idx := algo.IndexOf(sg.DestUIDs, uid) // Binary search. 2229 if idx >= 0 { 2230 included[idx] = true 2231 } 2232 } 2233 } 2234 algo.ApplyFilter(sg.DestUIDs, func(uid uint64, idx int) bool { return included[idx] }) 2235 } 2236 2237 func (sg *SubGraph) sortAndPaginateUsingFacet(ctx context.Context) error { 2238 if len(sg.facetsMatrix) == 0 { 2239 return nil 2240 } 2241 if len(sg.facetsMatrix) != len(sg.uidMatrix) { 2242 return errors.Errorf("Facet matrix and UID matrix mismatch: %d vs %d", 2243 len(sg.facetsMatrix), len(sg.uidMatrix)) 2244 } 2245 orderby := sg.Params.FacetOrder 2246 for i := 0; i < len(sg.uidMatrix); i++ { 2247 ul := sg.uidMatrix[i] 2248 fl := sg.facetsMatrix[i] 2249 uids := ul.Uids[:0] 2250 values := make([][]types.Val, 0, len(ul.Uids)) 2251 facetList := fl.FacetsList[:0] 2252 for j := 0; j < len(ul.Uids); j++ { 2253 var facet *api.Facet 2254 uid := ul.Uids[j] 2255 f := fl.FacetsList[j] 2256 uids = append(uids, uid) 2257 facetList = append(facetList, f) 2258 for _, it := range f.Facets { 2259 if it.Key == orderby { 2260 facet = it 2261 break 2262 } 2263 } 2264 if facet != nil { 2265 fVal, err := facets.ValFor(facet) 2266 if err != nil { 2267 return err 2268 } 2269 2270 values = append(values, []types.Val{fVal}) 2271 } else { 2272 values = append(values, []types.Val{{Value: nil}}) 2273 } 2274 } 2275 if len(values) == 0 { 2276 continue 2277 } 2278 if err := types.SortWithFacet(values, &pb.List{Uids: uids}, 2279 facetList, []bool{sg.Params.FacetOrderDesc}); err != nil { 2280 return err 2281 } 2282 sg.uidMatrix[i].Uids = uids 2283 // We need to update the facetmarix corresponding to changes to uidmatrix. 2284 sg.facetsMatrix[i].FacetsList = facetList 2285 } 2286 2287 if sg.Params.Count != 0 || sg.Params.Offset != 0 { 2288 // Apply the pagination. 2289 for i := 0; i < len(sg.uidMatrix); i++ { 2290 start, end := x.PageRange(sg.Params.Count, sg.Params.Offset, len(sg.uidMatrix[i].Uids)) 2291 sg.uidMatrix[i].Uids = sg.uidMatrix[i].Uids[start:end] 2292 // We also have to paginate the facetsMatrix for safety. 2293 sg.facetsMatrix[i].FacetsList = sg.facetsMatrix[i].FacetsList[start:end] 2294 } 2295 } 2296 2297 // Update the destUids as we might have removed some UIDs. 2298 sg.updateDestUids() 2299 return nil 2300 } 2301 2302 func (sg *SubGraph) sortAndPaginateUsingVar(ctx context.Context) error { 2303 // nil has a different meaning from an initialized map of zero length here. If the variable 2304 // didn't return any values then uidToVal would be an empty with zero length. If the variable 2305 // was used before definition, uidToVal would be nil. 2306 if sg.Params.uidToVal == nil { 2307 return errors.Errorf("Variable: [%s] used before definition.", sg.Params.Order[0].Attr) 2308 } 2309 2310 for i := 0; i < len(sg.uidMatrix); i++ { 2311 ul := sg.uidMatrix[i] 2312 uids := make([]uint64, 0, len(ul.Uids)) 2313 values := make([][]types.Val, 0, len(ul.Uids)) 2314 for _, uid := range ul.Uids { 2315 v, ok := sg.Params.uidToVal[uid] 2316 if !ok { 2317 // We skip the UIDs which don't have a value. 2318 continue 2319 } 2320 values = append(values, []types.Val{v}) 2321 uids = append(uids, uid) 2322 } 2323 if len(values) == 0 { 2324 continue 2325 } 2326 if err := types.Sort(values, &pb.List{Uids: uids}, []bool{sg.Params.Order[0].Desc}); err != nil { 2327 return err 2328 } 2329 sg.uidMatrix[i].Uids = uids 2330 } 2331 2332 if sg.Params.Count != 0 || sg.Params.Offset != 0 { 2333 // Apply the pagination. 2334 for i := 0; i < len(sg.uidMatrix); i++ { 2335 start, end := x.PageRange(sg.Params.Count, sg.Params.Offset, len(sg.uidMatrix[i].Uids)) 2336 sg.uidMatrix[i].Uids = sg.uidMatrix[i].Uids[start:end] 2337 } 2338 } 2339 2340 // Update the destUids as we might have removed some UIDs. 2341 sg.updateDestUids() 2342 return nil 2343 } 2344 2345 // isValidArg checks if arg passed is valid keyword. 2346 func isValidArg(a string) bool { 2347 switch a { 2348 case "numpaths", "from", "to", "orderasc", "orderdesc", "first", "offset", "after", "depth", 2349 "minweight", "maxweight": 2350 return true 2351 } 2352 return false 2353 } 2354 2355 // isValidFuncName checks if fn passed is valid keyword. 2356 func isValidFuncName(f string) bool { 2357 switch f { 2358 case "anyofterms", "allofterms", "val", "regexp", "anyoftext", "alloftext", 2359 "has", "uid", "uid_in", "anyof", "allof", "type", "match": 2360 return true 2361 } 2362 return isInequalityFn(f) || types.IsGeoFunc(f) 2363 } 2364 2365 func isInequalityFn(f string) bool { 2366 switch f { 2367 case "eq", "le", "ge", "gt", "lt": 2368 return true 2369 } 2370 return false 2371 } 2372 2373 func isAggregatorFn(f string) bool { 2374 switch f { 2375 case "min", "max", "sum", "avg": 2376 return true 2377 } 2378 return false 2379 } 2380 2381 func isUidFnWithoutVar(f *gql.Function) bool { 2382 return f != nil && f.Name == "uid" && len(f.NeedsVar) == 0 2383 } 2384 2385 func getNodeTypes(ctx context.Context, sg *SubGraph) ([]string, error) { 2386 temp := &SubGraph{ 2387 Attr: "dgraph.type", 2388 SrcUIDs: sg.DestUIDs, 2389 ReadTs: sg.ReadTs, 2390 } 2391 taskQuery, err := createTaskQuery(temp) 2392 if err != nil { 2393 return nil, err 2394 } 2395 result, err := worker.ProcessTaskOverNetwork(ctx, taskQuery) 2396 if err != nil { 2397 return nil, err 2398 } 2399 return getPredsFromVals(result.ValueMatrix), nil 2400 } 2401 2402 // getPredicatesFromTypes returns the list of preds contained in the given types. 2403 func getPredicatesFromTypes(types []string) []string { 2404 var preds []string 2405 2406 for _, typeName := range types { 2407 typeDef, ok := schema.State().GetType(typeName) 2408 if !ok { 2409 continue 2410 } 2411 2412 for _, field := range typeDef.Fields { 2413 preds = append(preds, field.Predicate) 2414 } 2415 } 2416 return preds 2417 } 2418 2419 // getReversePredicates queries the schema and returns a list of the reverse 2420 // predicates that exist within the given preds. 2421 func getReversePredicates(ctx context.Context, preds []string) ([]string, error) { 2422 var rpreds []string 2423 predMap := make(map[string]bool) 2424 for _, pred := range preds { 2425 predMap[pred] = true 2426 } 2427 2428 schs, err := worker.GetSchemaOverNetwork(ctx, &pb.SchemaRequest{Predicates: preds}) 2429 if err != nil { 2430 return nil, err 2431 } 2432 2433 for _, sch := range schs { 2434 if _, ok := predMap[sch.Predicate]; !ok { 2435 continue 2436 } 2437 if !sch.Reverse { 2438 continue 2439 } 2440 rpreds = append(rpreds, "~"+sch.Predicate) 2441 } 2442 return rpreds, nil 2443 } 2444 2445 // GetAllPredicates returns the list of all the unique predicates present in the list of subgraphs. 2446 func GetAllPredicates(subGraphs []*SubGraph) []string { 2447 predicatesMap := make(map[string]struct{}) 2448 for _, sg := range subGraphs { 2449 sg.getAllPredicates(predicatesMap) 2450 } 2451 predicates := make([]string, 0, len(predicatesMap)) 2452 for predicate := range predicatesMap { 2453 predicates = append(predicates, predicate) 2454 } 2455 return predicates 2456 } 2457 2458 func (sg *SubGraph) getAllPredicates(predicates map[string]struct{}) { 2459 if len(sg.Attr) != 0 { 2460 predicates[sg.Attr] = struct{}{} 2461 } 2462 for _, o := range sg.Params.Order { 2463 predicates[o.Attr] = struct{}{} 2464 } 2465 for _, pred := range sg.Params.groupbyAttrs { 2466 predicates[pred.Attr] = struct{}{} 2467 } 2468 for _, filter := range sg.Filters { 2469 filter.getAllPredicates(predicates) 2470 } 2471 for _, child := range sg.Children { 2472 child.getAllPredicates(predicates) 2473 } 2474 } 2475 2476 // UidsToHex converts the new UIDs to hex string. 2477 func UidsToHex(m map[string]uint64) map[string]string { 2478 res := make(map[string]string) 2479 for k, v := range m { 2480 res[k] = fmt.Sprintf("%#x", v) 2481 } 2482 return res 2483 } 2484 2485 // Request wraps the state that is used when executing query. 2486 // Initially ReadTs, Cache and GqlQuery are set. 2487 // Subgraphs, Vars and Latency are filled when processing query. 2488 type Request struct { 2489 ReadTs uint64 // ReadTs for the transaction. 2490 Cache int // 0 represents use txn cache, 1 represents not to use cache. 2491 Latency *Latency 2492 GqlQuery *gql.Result 2493 2494 Subgraphs []*SubGraph 2495 2496 Vars map[string]varValue 2497 } 2498 2499 // ProcessQuery processes query part of the request (without mutations). 2500 // Fills Subgraphs and Vars. 2501 // It can process multiple query blocks that are part of the query.. 2502 func (req *Request) ProcessQuery(ctx context.Context) (err error) { 2503 span := otrace.FromContext(ctx) 2504 stop := x.SpanTimer(span, "query.ProcessQuery") 2505 defer stop() 2506 2507 // doneVars stores the processed variables. 2508 req.Vars = make(map[string]varValue) 2509 loopStart := time.Now() 2510 queries := req.GqlQuery.Query 2511 // first loop converts queries to SubGraph representation and populates ReadTs And Cache. 2512 for i := 0; i < len(queries); i++ { 2513 gq := queries[i] 2514 2515 if gq == nil || (len(gq.UID) == 0 && gq.Func == nil && len(gq.NeedsVar) == 0 && 2516 gq.Alias != "shortest" && !gq.IsEmpty) { 2517 return errors.Errorf("Invalid query. No function used at root and no aggregation" + 2518 " or math variables found in the body.") 2519 } 2520 sg, err := ToSubGraph(ctx, gq) 2521 if err != nil { 2522 return errors.Wrapf(err, "while converting to subgraph") 2523 } 2524 sg.recurse(func(sg *SubGraph) { 2525 sg.ReadTs = req.ReadTs 2526 sg.Cache = req.Cache 2527 }) 2528 span.Annotate(nil, "Query parsed") 2529 req.Subgraphs = append(req.Subgraphs, sg) 2530 } 2531 req.Latency.Parsing += time.Since(loopStart) 2532 2533 execStart := time.Now() 2534 hasExecuted := make([]bool, len(req.Subgraphs)) 2535 numQueriesDone := 0 2536 2537 // canExecute returns true if a query block is ready to execute with all the variables 2538 // that it depends on are already populated or are defined in the same block. 2539 canExecute := func(idx int) bool { 2540 queryVars := req.GqlQuery.QueryVars[idx] 2541 for _, v := range queryVars.Needs { 2542 // here we check if this block defines the variable v. 2543 var selfDep bool 2544 for _, vd := range queryVars.Defines { 2545 if v == vd { 2546 selfDep = true 2547 break 2548 } 2549 } 2550 // The variable should be defined in this block or should have already been 2551 // populated by some other block, otherwise we are not ready to execute yet. 2552 _, ok := req.Vars[v] 2553 if !ok && !selfDep { 2554 return false 2555 } 2556 } 2557 return true 2558 } 2559 2560 var shortestSg []*SubGraph 2561 for i := 0; i < len(req.Subgraphs) && numQueriesDone < len(req.Subgraphs); i++ { 2562 errChan := make(chan error, len(req.Subgraphs)) 2563 var idxList []int 2564 // If we have N blocks in a query, it can take a maximum of N iterations for all of them 2565 // to be executed. 2566 for idx := 0; idx < len(req.Subgraphs); idx++ { 2567 if hasExecuted[idx] { 2568 continue 2569 } 2570 sg := req.Subgraphs[idx] 2571 // Check the list for the requires variables. 2572 if !canExecute(idx) { 2573 continue 2574 } 2575 2576 err = sg.recursiveFillVars(req.Vars) 2577 if err != nil { 2578 return err 2579 } 2580 hasExecuted[idx] = true 2581 numQueriesDone++ 2582 idxList = append(idxList, idx) 2583 // A query doesn't need to be executed if 2584 // 1. It just does aggregation and math functions which is when sg.Params.IsEmpty is true. 2585 // 2. Its has an inequality fn at root without any args which can happen when it uses 2586 // value variables for args which don't expand to any value. 2587 if sg.Params.IsEmpty || isEmptyIneqFnWithVar(sg) { 2588 errChan <- nil 2589 continue 2590 } 2591 2592 if sg.Params.Alias == "shortest" { 2593 // We allow only one shortest path block per query. 2594 go func() { 2595 shortestSg, err = shortestPath(ctx, sg) 2596 errChan <- err 2597 }() 2598 } else if sg.Params.Recurse { 2599 go func() { 2600 errChan <- recurse(ctx, sg) 2601 }() 2602 } else { 2603 go ProcessGraph(ctx, sg, nil, errChan) 2604 } 2605 } 2606 2607 var ferr error 2608 // Wait for the execution that was started in this iteration. 2609 for i := 0; i < len(idxList); i++ { 2610 if err = <-errChan; err != nil { 2611 ferr = err 2612 continue 2613 } 2614 } 2615 if ferr != nil { 2616 return ferr 2617 } 2618 2619 // If the executed subgraph had some variable defined in it, Populate it in the map. 2620 for _, idx := range idxList { 2621 sg := req.Subgraphs[idx] 2622 2623 var sgPath []*SubGraph 2624 if err := sg.populateVarMap(req.Vars, sgPath); err != nil { 2625 return err 2626 } 2627 if err := sg.populatePostAggregation(req.Vars, []*SubGraph{}, nil); err != nil { 2628 return err 2629 } 2630 } 2631 } 2632 2633 // Ensure all the queries are executed. 2634 for _, it := range hasExecuted { 2635 if !it { 2636 return errors.Errorf("Query couldn't be executed") 2637 } 2638 } 2639 req.Latency.Processing += time.Since(execStart) 2640 2641 // If we had a shortestPath SG, append it to the result. 2642 if len(shortestSg) != 0 { 2643 req.Subgraphs = append(req.Subgraphs, shortestSg...) 2644 } 2645 return nil 2646 } 2647 2648 // ExecutionResult holds the result of running a query. 2649 type ExecutionResult struct { 2650 Subgraphs []*SubGraph 2651 SchemaNode []*pb.SchemaNode 2652 Types []*pb.TypeUpdate 2653 } 2654 2655 // Process handles a query request. 2656 func (req *Request) Process(ctx context.Context) (er ExecutionResult, err error) { 2657 err = req.ProcessQuery(ctx) 2658 if err != nil { 2659 return er, err 2660 } 2661 er.Subgraphs = req.Subgraphs 2662 2663 schemaProcessingStart := time.Now() 2664 if req.GqlQuery.Schema != nil { 2665 if er.SchemaNode, err = worker.GetSchemaOverNetwork(ctx, req.GqlQuery.Schema); err != nil { 2666 return er, errors.Wrapf(err, "while fetching schema") 2667 } 2668 if er.Types, err = worker.GetTypes(ctx, req.GqlQuery.Schema); err != nil { 2669 return er, errors.Wrapf(err, "while fetching types") 2670 } 2671 } 2672 req.Latency.Processing += time.Since(schemaProcessingStart) 2673 2674 return er, nil 2675 } 2676 2677 // StripBlankNode returns a copy of the map where all the keys have the blank node prefix removed. 2678 func StripBlankNode(mp map[string]uint64) map[string]uint64 { 2679 temp := make(map[string]uint64) 2680 for k, v := range mp { 2681 if strings.HasPrefix(k, "_:") { 2682 temp[k[2:]] = v 2683 } 2684 } 2685 return temp 2686 }