Ask a Question

Value Variables in DQL

Value variables store scalar values in DQL. Value variables are a map from the UIDs of the enclosing block to the corresponding values.

The following are examples of value variables:

  • varName as scalarPredicate
  • varName as count(predicate)
  • varName as avg(...)
  • varName as math(...)

These variables map to the following types: int, float, String, dateTime, default, geo, bool

It only makes sense to use the values from a value variable in a context that matches the same UIDs - if used in a block matching different UIDs the value variable is undefined.

It is an error to define a value variable but not use it elsewhere in the query.

Value variables are used by extracting the values with val(var-name), or by extracting the UIDs with uid(var-name).

Facet values can be stored in value variables.

Query Example: The number of movie roles played by the actors of the 80’s classic “The Princess Bride”. Query variable pbActors matches the UIDs of all actors from the movie. Value variable roles is thus a map from actor UID to number of roles. Value variable roles can be used in the totalRoles query block because that query block also matches the pbActors UIDs, so the actor to number of roles map is available.

{
  var(func:allofterms(name@en, "The Princess Bride")) {
    starring {
      pbActors as performance.actor {
        roles as count(actor.film)
      }
    }
  }
  totalRoles(func: uid(pbActors), orderasc: val(roles)) {
    name@en
    numRoles : val(roles)
  }
}
curl localhost:8080/query -XPOST -d '
blahblah' | python -m json.tool | less
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
    
	"github.com/dgraph-io/dgo"
	"github.com/dgraph-io/dgo/protos/api"
    
	"google.golang.org/grpc"
)

var (
	dgraph = flag.String("d", "127.0.0.1:9080", "Dgraph Alpha address")
)

func main() {
	flag.Parse()
	conn, err := grpc.Dial(*dgraph, grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	dg := dgo.NewDgraphClient(api.NewDgraphClient(conn))
    
	resp, err := dg.NewTxn().Query(context.Background(), `blahblah`)
	
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Response: %s\n", resp.Json)
}
import io.dgraph.DgraphClient;
import io.dgraph.DgraphGrpc;
import io.dgraph.DgraphGrpc.DgraphStub;
import io.dgraph.DgraphProto.Response;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

import java.util.Map;

public class App {

    public static void main(final String[] args) {
        ManagedChannel channel =
            ManagedChannelBuilder.forAddress("localhost", 9080).usePlaintext(true).build();
        DgraphStub stub = DgraphGrpc.newStub(channel);
        DgraphClient dgraphClient = new DgraphClient(stub);

        String query = "blahblah";

    
        Response res = dgraphClient.newTransaction().query(query);
    
        System.out.printf("Response: %s", res.getJson().toStringUtf8());
    }
}

import pydgraph
import json

def main():
    client_stub = pydgraph.DgraphClientStub("localhost:9080")
    client = pydgraph.DgraphClient(client_stub)
    query = """blahblah"""
    res = client.txn(read_only=True).query(query)
    print('Response: {}'.format(json.loads(res.json)))

    client_stub.close()


if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        print('Error: {}'.format(e))

const dgraph = require("dgraph-js");
const grpc = require("grpc");

async function main() {
  const clientStub = new dgraph.DgraphClientStub("localhost:9080", grpc.credentials.createInsecure());
  const dgraphClient = new dgraph.DgraphClient(clientStub);

  const query = `blahblah`;
  const response = await dgraphClient.newTxn().query(query);
  console.log("Response: ", JSON.stringify(response.getJson()));

  clientStub.close();
}

main().then().catch((e) => {
  console.log("ERROR: ", e);
});
const dgraph = require("dgraph-js-http");

async function main() {
  const clientStub = new dgraph.DgraphClientStub("http://localhost:8080");
  const dgraphClient = new dgraph.DgraphClient(clientStub);

  const query = `blahblah`;
  const response = await dgraphClient.newTxn().query(query);
  console.log("Response: ", JSON.stringify(response.data));
}

main().then().catch((e) => {
  console.log("ERROR: ", e);
});
Response

Value variables can be used in place of UID variables by extracting the UID list from the map.

Query Example: The same query as the previous example, but using value variable roles for matching UIDs in the totalRoles query block.

{
  var(func:allofterms(name@en, "The Princess Bride")) {
    starring {
      performance.actor {
        roles as count(actor.film)
      }
    }
  }
  totalRoles(func: uid(roles), orderasc: val(roles)) {
    name@en
    numRoles : val(roles)
  }
}
curl localhost:8080/query -XPOST -d '
blahblah' | python -m json.tool | less
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
    
	"github.com/dgraph-io/dgo"
	"github.com/dgraph-io/dgo/protos/api"
    
	"google.golang.org/grpc"
)

var (
	dgraph = flag.String("d", "127.0.0.1:9080", "Dgraph Alpha address")
)

func main() {
	flag.Parse()
	conn, err := grpc.Dial(*dgraph, grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	dg := dgo.NewDgraphClient(api.NewDgraphClient(conn))
    
	resp, err := dg.NewTxn().Query(context.Background(), `blahblah`)
	
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Response: %s\n", resp.Json)
}
import io.dgraph.DgraphClient;
import io.dgraph.DgraphGrpc;
import io.dgraph.DgraphGrpc.DgraphStub;
import io.dgraph.DgraphProto.Response;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

import java.util.Map;

public class App {

    public static void main(final String[] args) {
        ManagedChannel channel =
            ManagedChannelBuilder.forAddress("localhost", 9080).usePlaintext(true).build();
        DgraphStub stub = DgraphGrpc.newStub(channel);
        DgraphClient dgraphClient = new DgraphClient(stub);

        String query = "blahblah";

    
        Response res = dgraphClient.newTransaction().query(query);
    
        System.out.printf("Response: %s", res.getJson().toStringUtf8());
    }
}

import pydgraph
import json

def main():
    client_stub = pydgraph.DgraphClientStub("localhost:9080")
    client = pydgraph.DgraphClient(client_stub)
    query = """blahblah"""
    res = client.txn(read_only=True).query(query)
    print('Response: {}'.format(json.loads(res.json)))

    client_stub.close()


if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        print('Error: {}'.format(e))

const dgraph = require("dgraph-js");
const grpc = require("grpc");

async function main() {
  const clientStub = new dgraph.DgraphClientStub("localhost:9080", grpc.credentials.createInsecure());
  const dgraphClient = new dgraph.DgraphClient(clientStub);

  const query = `blahblah`;
  const response = await dgraphClient.newTxn().query(query);
  console.log("Response: ", JSON.stringify(response.getJson()));

  clientStub.close();
}

main().then().catch((e) => {
  console.log("ERROR: ", e);
});
const dgraph = require("dgraph-js-http");

async function main() {
  const clientStub = new dgraph.DgraphClientStub("http://localhost:8080");
  const dgraphClient = new dgraph.DgraphClient(clientStub);

  const query = `blahblah`;
  const response = await dgraphClient.newTxn().query(query);
  console.log("Response: ", JSON.stringify(response.data));
}

main().then().catch((e) => {
  console.log("ERROR: ", e);
});
Response

Variable Propagation

Like query variables, value variables can be used in other query blocks and in blocks nested within the defining block. When used in a block nested within the block that defines the variable, the value is computed as a sum of the variable for parent nodes along all paths to the point of use. This is called variable propagation.

For example:

{
  q(func: uid(0x01)) {
    myscore as math(1)          # A
    friends {                   # B
      friends {                 # C
        ...myscore...
      }
    }
  }
}

At line A, a value variable myscore is defined as mapping node with UID 0x01 to value 1. At B, the value for each friend is still 1: there is only one path to each friend. Traversing the friend edge twice reaches the friends of friends. The variable myscore gets propagated such that each friend of friend will receive the sum of its parents values: if a friend of a friend is reachable from only one friend, the value is still 1, if they are reachable from two friends, the value is two and so on. That is, the value of myscore for each friend of friends inside the block marked C will be the number of paths to them.

The value that a node receives for a propagated variable is the sum of the values of all its parent nodes.

This propagation is useful, for example, in normalizing a sum across users, finding the number of paths between nodes and accumulating a sum through a graph.

Query Example: For each Harry Potter movie, the number of roles played by actor Warwick Davis.

{
    num_roles(func: eq(name@en, "Warwick Davis")) @cascade @normalize {

    paths as math(1)  # records number of paths to each character

    actor : name@en

    actor.film {
      performance.film @filter(allofterms(name@en, "Harry Potter")) {
        film_name : name@en
        characters : math(paths)  # how many paths (i.e. characters) reach this film
      }
    }
  }
}
curl localhost:8080/query -XPOST -d '
blahblah' | python -m json.tool | less
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
    
	"github.com/dgraph-io/dgo"
	"github.com/dgraph-io/dgo/protos/api"
    
	"google.golang.org/grpc"
)

var (
	dgraph = flag.String("d", "127.0.0.1:9080", "Dgraph Alpha address")
)

func main() {
	flag.Parse()
	conn, err := grpc.Dial(*dgraph, grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	dg := dgo.NewDgraphClient(api.NewDgraphClient(conn))
    
	resp, err := dg.NewTxn().Query(context.Background(), `blahblah`)
	
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Response: %s\n", resp.Json)
}
import io.dgraph.DgraphClient;
import io.dgraph.DgraphGrpc;
import io.dgraph.DgraphGrpc.DgraphStub;
import io.dgraph.DgraphProto.Response;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

import java.util.Map;

public class App {

    public static void main(final String[] args) {
        ManagedChannel channel =
            ManagedChannelBuilder.forAddress("localhost", 9080).usePlaintext(true).build();
        DgraphStub stub = DgraphGrpc.newStub(channel);
        DgraphClient dgraphClient = new DgraphClient(stub);

        String query = "blahblah";

    
        Response res = dgraphClient.newTransaction().query(query);
    
        System.out.printf("Response: %s", res.getJson().toStringUtf8());
    }
}

import pydgraph
import json

def main():
    client_stub = pydgraph.DgraphClientStub("localhost:9080")
    client = pydgraph.DgraphClient(client_stub)
    query = """blahblah"""
    res = client.txn(read_only=True).query(query)
    print('Response: {}'.format(json.loads(res.json)))

    client_stub.close()


if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        print('Error: {}'.format(e))

const dgraph = require("dgraph-js");
const grpc = require("grpc");

async function main() {
  const clientStub = new dgraph.DgraphClientStub("localhost:9080", grpc.credentials.createInsecure());
  const dgraphClient = new dgraph.DgraphClient(clientStub);

  const query = `blahblah`;
  const response = await dgraphClient.newTxn().query(query);
  console.log("Response: ", JSON.stringify(response.getJson()));

  clientStub.close();
}

main().then().catch((e) => {
  console.log("ERROR: ", e);
});
const dgraph = require("dgraph-js-http");

async function main() {
  const clientStub = new dgraph.DgraphClientStub("http://localhost:8080");
  const dgraphClient = new dgraph.DgraphClient(clientStub);

  const query = `blahblah`;
  const response = await dgraphClient.newTxn().query(query);
  console.log("Response: ", JSON.stringify(response.data));
}

main().then().catch((e) => {
  console.log("ERROR: ", e);
});
Response

Query Example: Each actor who has been in a Peter Jackson movie and the fraction of Peter Jackson movies they have appeared in.

{
    movie_fraction(func:eq(name@en, "Peter Jackson")) @normalize {

    paths as math(1)
    total_films : num_films as count(director.film)
    director : name@en

    director.film {
      starring {
        performance.actor {
          fraction : math(paths / (num_films/paths))
          actor : name@en
        }
      }
    }
  }
}
curl localhost:8080/query -XPOST -d '
blahblah' | python -m json.tool | less
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
    
	"github.com/dgraph-io/dgo"
	"github.com/dgraph-io/dgo/protos/api"
    
	"google.golang.org/grpc"
)

var (
	dgraph = flag.String("d", "127.0.0.1:9080", "Dgraph Alpha address")
)

func main() {
	flag.Parse()
	conn, err := grpc.Dial(*dgraph, grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	dg := dgo.NewDgraphClient(api.NewDgraphClient(conn))
    
	resp, err := dg.NewTxn().Query(context.Background(), `blahblah`)
	
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Response: %s\n", resp.Json)
}
import io.dgraph.DgraphClient;
import io.dgraph.DgraphGrpc;
import io.dgraph.DgraphGrpc.DgraphStub;
import io.dgraph.DgraphProto.Response;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

import java.util.Map;

public class App {

    public static void main(final String[] args) {
        ManagedChannel channel =
            ManagedChannelBuilder.forAddress("localhost", 9080).usePlaintext(true).build();
        DgraphStub stub = DgraphGrpc.newStub(channel);
        DgraphClient dgraphClient = new DgraphClient(stub);

        String query = "blahblah";

    
        Response res = dgraphClient.newTransaction().query(query);
    
        System.out.printf("Response: %s", res.getJson().toStringUtf8());
    }
}

import pydgraph
import json

def main():
    client_stub = pydgraph.DgraphClientStub("localhost:9080")
    client = pydgraph.DgraphClient(client_stub)
    query = """blahblah"""
    res = client.txn(read_only=True).query(query)
    print('Response: {}'.format(json.loads(res.json)))

    client_stub.close()


if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        print('Error: {}'.format(e))

const dgraph = require("dgraph-js");
const grpc = require("grpc");

async function main() {
  const clientStub = new dgraph.DgraphClientStub("localhost:9080", grpc.credentials.createInsecure());
  const dgraphClient = new dgraph.DgraphClient(clientStub);

  const query = `blahblah`;
  const response = await dgraphClient.newTxn().query(query);
  console.log("Response: ", JSON.stringify(response.getJson()));

  clientStub.close();
}

main().then().catch((e) => {
  console.log("ERROR: ", e);
});
const dgraph = require("dgraph-js-http");

async function main() {
  const clientStub = new dgraph.DgraphClientStub("http://localhost:8080");
  const dgraphClient = new dgraph.DgraphClient(clientStub);

  const query = `blahblah`;
  const response = await dgraphClient.newTxn().query(query);
  console.log("Response: ", JSON.stringify(response.data));
}

main().then().catch((e) => {
  console.log("ERROR: ", e);
});
Response

More examples can be found in two Dgraph blog posts about using variable propagation for recommendation engines (post 1, post 2).