Expressions#
Query arguments are written as expressions compiled at startup using expr-lang/expr. Each expression has access to the built-in functions, globals, and any user-defined expressions.
Tip: Use
edg replto try any expression interactively without a database connection. See REPL for details.
Functions#
Jump to: Aggregation · Batch · Binary · Conditionals · Constants & variables · Dates & times · Formatting · Generation · Geographic · JSON & arrays · LLM · Math · Numeric distributions · Reference data · Results · Sequences · Set selection · UUIDs & identifiers · Vectors
Looking for usage examples? See Argument Examples.
These are edg’s built-in functions, available in any expression context (args:, expressions:, globals). They generate data, reference datasets, aggregate values, and control execution flow.
Aggregation#
| Function | Returns | Description |
|---|---|---|
avg(name, field) | float64 | Average of a numeric field across all rows in a named dataset.avg('fetch_products', 'price') -> 19.39 |
count(name) | int | Number of rows in a named dataset.count('fetch_products') -> 5 |
distinct(name, field) | int | Number of distinct values for a field in a named dataset.distinct('fetch_products', 'category') -> 3 |
max(name, field) | float64 | Maximum value of a numeric field in a named dataset.max('fetch_products', 'price') -> 49.99 |
median(name, field) | float64 | Median (50th percentile) of a numeric field in a named dataset. Equivalent to percentile(name, field, 50).median('fetch_orders', 'total') -> 24.50 |
min(name, field) | float64 | Minimum value of a numeric field in a named dataset.min('fetch_products', 'price') -> 1.99 |
percentile(name, field, p) | float64 | Pth percentile of a numeric field, using linear interpolation between the two nearest ranks. p is a percentage in [0, 100]; out-of-range values are an error. p is always the last argument.percentile('fetch_orders', 'total', 95) -> 98.20 |
stddev(name, field) | float64 | Population standard deviation of a numeric field (divides by N, not N-1).stddev('fetch_products', 'price') -> 17.84 |
sum(name, field) | float64 | Sum of a numeric field across all rows in a named dataset.sum('fetch_products', 'price') -> 96.95 |
variance(name, field) | float64 | Population variance of a numeric field (divides by N, not N-1).variance('fetch_products', 'price') -> 318.27 |
Every aggregate (sum, avg, min, max, median, stddev, variance, percentile) also accepts a single-array form in addition to the (dataset, field) form. These names shadow expr-lang’s builtin aggregates, so edg reimplements them and both call shapes work.
| Array form | Dataset form |
|---|---|
median(prices) | median('fetch_orders', 'total') |
percentile(prices, 95) | percentile('fetch_orders', 'total', 95) |
stddev(prices) | stddev('fetch_orders', 'total') |
sum([1, 2, 3]) | sum('fetch_orders', 'total') |
For percentile the p is always the last argument, so the array form takes 2 arguments and the dataset form takes 3. Non-numeric elements in an array are skipped, and empty input returns 0 (including for min and max).
Batch#
| Function | Returns | Description |
|---|---|---|
__sep__ | string | Driver-aware batch field separator. A query-text token that is replaced with the SQL function producing the ASCII unit separator character (char 31) used to delimit values within batch-expanded placeholders. Resolves to chr(31) for pgx, CHAR(31) for MySQL and MSSQL, codepoints-to-string(31) for Oracle, CODE_POINTS_TO_STRING([31]) for Spanner. Can be used in any argument position within SQL. Always use __sep__ instead of a literal comma. Generated values may contain commas, which would silently corrupt your data.string_to_array('$1', __sep__) |
batch(n) | [][]any | Returns sequential integers [0, n) as batch arg sets,batch(3) -> [[0], [1], [2]] |
gen_batch(total, batchSize, pattern) | [][]any | Generates total values using gofakeit pattern, grouped into batches of batchSize. Each batch arg is a string of generated values delimited by the ASCII unit separator (char 31, \x1f).gen_batch(4, 2, 'firstname') -> [["Alice\x1fBob"], ["Carol\x1fDave"]] |
Binary#
| Function | Returns | Description |
|---|---|---|
bit(n) | string | Random fixed-length bit string of exactly n bits.bit(8) -> 10110011 |
blob(n) | []byte | Random n bytes as raw binary data. Works across all databases (PostgreSQL, MySQL, Oracle, MSSQL) via bind parameters. Use this for BLOB, BYTEA, VARBINARY, and RAW columns.blob(1024) -> (1024 random bytes) |
bytes(n) | string | Random n bytes as a hex-encoded string with \x prefix. PostgreSQL/CockroachDB only. For cross-database binary data, use blob(n) instead.bytes(4) -> \x1a2b3c4d |
varbit(n) | string | Random variable-length bit string of 1 to n bits.varbit(8) -> 10110 |
Conditionals#
| Function | Returns | Description |
|---|---|---|
coalesce(v1, v2, ...) | any | Returns the first non-nil value from arguments.coalesce(nil, 'default') -> default |
cond(predicate, trueVal, falseVal) | any | Returns trueVal if predicate is true, falseVal otherwise.cond(true, 'yes', 'no') -> yes |
fail(message) | error | Returns an error that stops the current worker gracefully. Useful with ?? to catch unexpected values: {'a': 1}['x'] ?? fail('unknown key').fail('unexpected region') -> (worker stops with error) |
fatal(message) | void | Terminates the entire process immediately. Use when an unexpected value should halt all workers, not just the current one.fatal('missing required config') -> (process exits) |
null | nil | Null literal. Alias for nil, for users more familiar with SQL/JSON terminology. Not a function, use as a bare variable.const(null) -> NULL |
nullable(expr, probability) | any | Returns NULL with probability (0.0-1.0), otherwise returns the expression result.nullable(gen('email'), 0.3) -> NULL |
Constants & variables#
| Function | Returns | Description |
|---|---|---|
arg(index) | any | Returns the value of a previously evaluated arg by its zero-based index or name. Enables dependent columns where later args reference earlier ones.arg(0) -> "Alice"arg('email') -> "alice@example.com" (with named args) |
const(value) | any | Returns the value as-is. Useful for literal constants.const(42) -> 42 |
env_nil(name) | any | Returns the value of an environment variable as a string, or nil if unset. Unlike env(), does not error on missing variables. Designed for use with coalesce() to provide defaults: int(coalesce(env_nil('PORT'), 8080)). Always returns a string when the variable exists, so wrap with int() or float() when arithmetic is needed.env_nil('MISSING') -> nilenv_nil('HOST') -> localhost |
env(name) | string | Returns the value of a given environment variable (or an error if one doesn’t exist with that name). Missing variables are caught at config load time, before any queries run. Can be composed with other functions, e.g. upper(env('HOST')). For numeric values, use expr-lang conversion: int(env('PORT')), float(env('RATE')).env('API_KEY') -> ca3864628a8f29d644e1... |
expr(expression) | any | Evaluates an arithmetic expression. Alias for const, the expr engine handles the arithmetic.expr(2 + 3) -> 5 |
field(name) | any | Evaluates a named field from the current query’s object: object. Requires object: to be set on the query. Use in args to cherry-pick fields or control ordering.field('email') -> alice@example.com |
global_iter() | int64 | Monotonic iteration counter shared across all workers in a stage. Increments by 1 each time any worker calls RunIteration. Never resets. Use for time-series seasonality and data drift patterns.20.0 + 5.0 * sin(2.0 * pi * global_iter() / 1000) -> 22.93... |
global(name) | any | Looks up a value from the globals section by name. Globals are also available directly as variables, so global('warehouses') and warehouses are equivalent.global('warehouses') -> 10 |
iter() | int | 1-based row counter for exec_batch / query_batch queries. Returns 1 for the first row, 2 for the second, etc. Resets at the start of each batch query. Useful for generating sequential IDs without a global sequence.iter() -> 1 |
local(name) | any | Returns the value of a named local variable. Locals can be defined on individual queries or transactions. Query-level locals override transaction locals when both exist. Locals are re-evaluated per row in batch mode. Useful for calling complete() once and accessing multiple fields.local("review").review_text -> "Great product!" |
obj(name, field) | any | Evaluates only the named field from an object, avoiding the cost of evaluating all fields.obj('order', 'product') -> Widget |
obj(name) | map | Evaluates all field expressions for a named object defined in the objects section and returns them as a map. Access individual fields with dot notation.obj('order').product -> Widget |
Dates & times#
| Function | Returns | Description |
|---|---|---|
after(base, min_offset, max_offset) | string | Random RFC3339 timestamp between min_offset and max_offset after base. Offsets are Go duration strings. base can be a string or a value from ref_same(), arg(), etc.after('2024-01-01T00:00:00Z', '1h', '24h') -> 2024-01-01T14:32:07Zafter(ref_same('parent').created_at, '1s', '24h') -> 2024-01-01T03:17:42Z |
before(base, min_offset, max_offset) | string | Random RFC3339 timestamp between min_offset and max_offset before base. Offsets are Go duration strings.before('2024-06-01T00:00:00Z', '1h', '24h') -> 2024-05-31T10:27:53Zbefore(ref_same('child').deleted_at, '1s', '24h') -> 2024-05-31T22:43:11Z |
date_offset(duration) | string | Returns the current time offset by duration, formatted as RFC3339.date_offset('-72h') -> 2026-04-08T10:00:00Z |
date(format, min, max) | string | Random timestamp formatted using a Go time format string.date('2006-01-02', '2020-01-01T00:00:00Z', '2025-01-01T00:00:00Z') -> 2023-07-15 |
duration(min, max) | string | Random duration between min and max (Go duration strings).duration('1h', '24h') -> 14h32m17s |
time(min, max) | string | Random time of day between min and max (HH:MM:SS format).time('08:00:00', '18:00:00') -> 14:32:07 |
timestamp(min, max) | string | Random timestamp between min and max (RFC3339).timestamp('2020-01-01T00:00:00Z', '2025-01-01T00:00:00Z') -> 2023-07-15T14:32:07Z |
timez(min, max) | string | Random time of day with +00:00 timezone suffix.timez('09:00:00', '17:00:00') -> 14:32:07+00:00 |
Formatting#
| Function | Returns | Description |
|---|---|---|
humanize(value, format) | string | Format numbers for human readability. Supported formats: bytes, ibytes, comma, and ordinal (1st, 2nd, 3rd).humanize(82854982, 'bytes') -> 83 MBhumanize(1234567, 'comma') -> 1,234,567humanize(3, 'ordinal') -> 3rd |
to_kb(bytes) | float64 | Convert bytes to kilobytes (floor division by 1,000).to_kb(82854) -> 82 |
to_mb(bytes) | float64 | Convert bytes to megabytes (floor division by 1,000,000).to_mb(82854982) -> 82 |
to_gb(bytes) | float64 | Convert bytes to gigabytes (floor division by 1,000,000,000).to_gb(82854982000) -> 82 |
to_tb(bytes) | float64 | Convert bytes to terabytes (floor division by 1,000,000,000,000).to_tb(82854982000000) -> 82 |
Generation#
| Function | Returns | Description |
|---|---|---|
bool() | bool | Random true or false. Useful as a coin flip with cond() and arg() for mutually exclusive columns.bool() -> true |
gen(pattern) | string | Generates a random value using gofakeit patterns (e.g. gen('number:1,100')).gen('number:1,10') -> 7 |
hash(value, algo) | string | Deterministic unkeyed hex digest of value. algo is one of md5 (32 chars), sha1 (40), sha256 (64), or crc32 (8). Unlike mask(), which is HMAC-keyed pseudonymization, hash() takes no key, so the same input yields the same digest across runs and machines. Intended for dedup keys and shard selection, not for pseudonymization or anything security-sensitive.hash('user@example.com', 'sha256') -> b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514 |
regex(pattern) | string | Generates a random string matching the given regular expression.regex('[A-Z]{3}-[0-9]{4}') -> ABK-7291 |
template(format, args...) | string | Formats a string using Go’s fmt.Sprintf syntax.template('ORD-%05d', seq(1, 1)) -> ORD-00001 |
uniq_across(pool, expression [, expression...] [, maxRetries]) | any | Cross-query uniqueness pool. Like uniq() but values are unique across all queries sharing the same pool name. The pool persists for the lifetime of the environment, so two seed queries using uniq_across('emails', "gen('email')") will never produce duplicates. Defaults to 100 retry attempts.uniq_across('emails', "gen('email')") -> alice@example.comuniq_across('ids', "gen('uuid')", 500) -> pool with custom max retriesuniq_across('names', "gen('first')", "gen('last')") -> composite cross-query uniqueness |
uniq(expression [, expression...] [, maxRetries]) | any | Evaluates one or more string expressions repeatedly until a unique value (or composite tuple) is produced. Defaults to 100 retry attempts; pass an optional integer as the last argument to override. Single expression - returns a single value: uniq("gen('airlineairportiata')") -> LAXComposite - pass multiple expressions to enforce cross-column uniqueness. Returns []any; index to pick each column. Same-row calls with identical expressions return a cached tuple:uniq("gen('first_name')", "gen('last_name')")[0] -> Aliceuniq("gen('first_name')", "gen('last_name')")[1] -> SmithSeen values persist across rows within a query and reset between queries. |
Geographic#
| Function | Returns | Description |
|---|---|---|
geo_bearing(lat1, lon1, lat2, lon2) | float64 | Initial compass bearing in degrees when travelling from the first point to the second. Always in the range [0, 360): 0 is north, 90 east, 180 south, 270 west.geo_bearing(51.5074, -0.1278, 48.8566, 2.3522) -> 148.1 |
geo_distance(lat1, lon1, lat2, lon2) | float64 | Great-circle distance in kilometres between two lat/lon points (haversine formula, earth radius 6371 km). Complements point/point_wkt/polygon - use it to derive a distance from generated geo columns.geo_distance(51.5074, -0.1278, 48.8566, 2.3522) -> 343.5 |
inet(cidr) | string | Random IP address within the given CIDR block.inet('192.168.1.0/24') -> 192.168.1.42 |
point_wkt(lat, lon, radiusKM) | string | Generates a random geographic point as a WKT string: POINT(lon lat).point_wkt(51.5, -0.1, 10.0) -> POINT(-0.082 51.513) |
point(lat, lon, radiusKM) | map | Generates a random geographic point within radiusKM of (lat, lon). Access fields with .lat and .lon.point(51.5, -0.1, 10.0).lat -> 51.513 |
polygon_wkt(lat, lon, minKM, maxKM, points) | string | Generates a jagged polygon with points vertices around (lat, lon), each at a random distance between minKM and maxKM. Returns a WKT POLYGON string. The ring is closed (first vertex repeated at end).polygon_wkt(51.1, -0.4, 5, 15, 6) -> POLYGON((-0.33 51.18, ...)) |
polygon(lat, lon, minKM, maxKM, points) | []map | Generates a jagged polygon with points vertices around (lat, lon), each at a random distance between minKM and maxKM. Returns a slice of maps with .lat and .lon fields. The ring is closed (first vertex repeated at end). Requires points >= 3.polygon(51.1, -0.4, 5, 15, 6)[0].lat -> 51.18 |
JSON & arrays#
| Function | Returns | Description |
|---|---|---|
array(minN, maxN, pattern) | string | PostgreSQL/CockroachDB array literal with a random number of elements.array(2, 4, 'email') -> {a@b.com,c@d.com,d@e.com} |
json_arr(minN, maxN, pattern) | string | Builds a JSON array of N random values (N in [minN, maxN]) generated by a gofakeit pattern.json_arr(1, 3, 'word') -> ["foo","bar"] |
json_obj(k1, v1, k2, v2, ...) | string | Builds a JSON object string from key-value pair arguments.json_obj('key', 'val') -> {"key":"val"} |
range(start, end[, step]) | []any | Generates an integer array from start to end (both inclusive). Step defaults to 1; use a negative step for descending ranges. Useful with set to avoid hand-written arrays.range(0, 23) -> [0, 1, 2, ..., 23]range(0, 10, 2) -> [0, 2, 4, 6, 8, 10]range(5, 0, -1) -> [5, 4, 3, 2, 1, 0] |
LLM#
| Function | Returns | Description |
|---|---|---|
complete_array(tool, prompt, count) | []map | Generates N structured items in a single LLM call. The tool schema is automatically wrapped in an array request. Returns []map for use with ref_each(). Memoized by (tool, prompt, count). Requires --complete-api-key or EDG_COMPLETE_API_KEY. See Complete.ref_each(complete_array("review", "Generate 5 reviews", 5)).review_text -> "Great product!" |
complete(tool, prompt) | map | Calls an LLM with a named tool schema and returns structured data as a map. Access fields with dot notation. Per-row memoization ensures multiple field accesses with the same tool and prompt make only one API call. Requires --complete-api-key or EDG_COMPLETE_API_KEY. See Complete.complete("review", "Review: Widget").review_text -> "Great product!"complete("review", "Review: Widget").rating -> 4 |
embed(text...) | string | Calls an external embedding API (OpenAI-compatible) and returns a vector literal. Variadic - multiple args are joined with a space. Requires --embed-api-key or EDG_EMBED_API_KEY. See Embed.embed('hello world') -> [0.0123,-0.0456,...]embed(field('name'), field('description')) -> [0.0789,...] |
Math#
| Function | Returns | Description |
|---|---|---|
abs(x) | float64 | Absolute value of x.abs(-5.0) -> 5 |
acos(x) | float64 | Arc cosine of x (result in radians).acos(1.0) -> 0 |
asin(x) | float64 | Arc sine of x (result in radians).asin(1.0) -> 1.5707... |
atan(x) | float64 | Arc tangent of x (result in radians).atan(1.0) -> 0.7853... |
atan2(y, x) | float64 | Two-argument arc tangent of y/x (result in radians). Handles quadrant correctly.atan2(1.0, 1.0) -> 0.7853... |
ceil(x) | float64 | Smallest integer greater than or equal to x.ceil(3.2) -> 4 |
cos(x) | float64 | Cosine of x (x in radians).cos(0.0) -> 1 |
floor(x) | float64 | Largest integer less than or equal to x.floor(3.7) -> 3 |
log(x) | float64 | Natural logarithm of x.log(1.0) -> 0 |
log10(x) | float64 | Base-10 logarithm of x.log10(100.0) -> 2 |
mod(x, y) | float64 | Floating-point remainder of x/y.mod(10.0, 3.0) -> 1 |
pi | float64 | The mathematical constant pi (3.14159…). Not a function - use as a bare variable.2 * pi -> 6.28318... |
pow(x, y) | float64 | x raised to the power y.pow(2.0, 10.0) -> 1024 |
round(x, places) | float64 | Round x to places decimal places.round(3.14159, 2) -> 3.14 |
sin(x) | float64 | Sine of x (x in radians).sin(pi / 2) -> 1 |
sqrt(x) | float64 | Square root of x.sqrt(144.0) -> 12 |
tan(x) | float64 | Tangent of x (x in radians).tan(pi / 4) -> 1 |
Numeric distributions#
| Function | Returns | Description |
|---|---|---|
beta.float(alpha, beta, min, max, precision)PRO | float64 | Beta-distributed random number in [min, max], rounded to precision decimal places. Alpha and beta control the shape: alpha=beta=1 is uniform, alpha<1 and beta<1 is U-shaped, alpha>1 and beta>1 is bell-shaped. Beta’s support is [0, 1], so min/max scale the draw (min + x*(max-min)) rather than clamping it - the full range is covered.beta.float(2, 5, 0, 1, 4) -> 0.2857 |
beta.n(alpha, beta, min, max, minN, maxN)PRO | string | N unique Beta-distributed values (N in [minN, maxN]) as a comma-separated string.beta.n(2, 5, 0, 100, 3, 5) -> 12,29,47,58 |
beta(alpha, beta, min, max)PRO | float64 | Beta-distributed random number in [min, max], rounded to 0 decimal places.beta(2, 5, 0, 100) -> 29 |
binomial.int(n, p)PRO | int | Binomial-distributed random integer: number of successes in n independent trials each with probability p. Result is in [0, n].binomial.int(100, 0.3) -> 31 |
binomial.n(n, p, minN, maxN)PRO | string | N unique Binomial-distributed values (N in [minN, maxN]) as a comma-separated string.binomial.n(100, 0.3, 3, 5) -> 27,31,34,38 |
empirical.float(samples, precision)PRO | float64 | Sample from the empirical CDF of observed data with precision. Interpolates between quantiles to generate new values matching the observed distribution shape.empirical.float([10, 20, 30, 40, 50], 2) -> 27.34 |
empirical.int(samples)PRO | float64 | Sample from the empirical CDF of observed data. Pass an array of observed values; the function builds a CDF and samples from it with linear interpolation.empirical.int([10, 20, 30, 40, 50]) -> 27 |
empirical.n(samples, minN, maxN)PRO | string | N unique values sampled from the empirical CDF (N in [minN, maxN]) as a comma-separated string.empirical.n([10, 20, 30, 40, 50], 3, 5) -> 14,27,33,48 |
exp.float(rate, min, max, precision)PRO | float64 | Exponentially-distributed random number in [min, max], rounded to precision decimal places.exp.float(0.5, 0, 100, 2) -> 3.72 |
exp.n(rate, min, max, minN, maxN)PRO | string | N unique exponentially-distributed values (N in [minN, maxN]) as a comma-separated string.exp.n(0.5, 0, 100, 3, 5) -> 1,4,9,17 |
exp(rate, min, max)PRO | float64 | Exponentially-distributed random number in [min, max], rounded to 0 decimal places.exp(0.5, 0, 100) -> 4 |
gamma.float(shape, rate, min, max, precision)PRO | float64 | Gamma-distributed random number in [min, max], rounded to precision decimal places. Mean is shape/rate. Useful for wait times, insurance claims.gamma.float(2, 1, 0, 100, 2) -> 1.87 |
gamma.n(shape, rate, min, max, minN, maxN)PRO | string | N unique Gamma-distributed values (N in [minN, maxN]) as a comma-separated string.gamma.n(2, 1, 0, 100, 3, 5) -> 1,2,4,7 |
gamma(shape, rate, min, max)PRO | float64 | Gamma-distributed random number in [min, max], rounded to 0 decimal places.gamma(2, 1, 0, 100) -> 2 |
lognorm.float(mu, sigma, min, max, precision)PRO | float64 | Log-normally-distributed random number in [min, max], rounded to precision decimal places.lognorm.float(1.0, 0.5, 1, 1000, 2) -> 3.42 |
lognorm.n(mu, sigma, min, max, minN, maxN)PRO | string | N unique log-normally-distributed values (N in [minN, maxN]) as a comma-separated string.lognorm.n(1.0, 0.5, 1, 1000, 3, 5) -> 2,3,5,9 |
lognorm(mu, sigma, min, max)PRO | float64 | Log-normally-distributed random number in [min, max], rounded to 0 decimal places.lognorm(1.0, 0.5, 1, 1000) -> 3 |
markov(group, states, matrix)PRO | any | Stateful Markov chain. group names the chain, so separate columns can run independent chains. states is an array of state labels; matrix is a flat array of transition probabilities (row-major, one row per state). Each worker maintains its own state across rows. Returns the current state label.markov('session', ['active', 'idle', 'offline'], [0.7, 0.2, 0.1, 0.3, 0.5, 0.2, 0.1, 0.1, 0.8]) -> active |
mvnorm(group, index, means, stddevs, correlations)PRO | float64 | Multivariate normal distribution. Generates correlated values across columns within the same row. group ties the columns together - all calls sharing a group name share one draw. index selects which dimension (0-based). means and stddevs are arrays of per-dimension parameters. correlations holds only the off-diagonal coefficients: [r] for 2 dimensions, [r12, r13, r23] for 3. Values for the same row are cached so all dimensions share the same random draw.mvnorm('pair', 0, [100, 50], [10, 5], [0.8]) -> 107.3 |
norm.float(mean, stddev, min, max, precision)PRO | float64 | Normally-distributed random number in [min, max], rounded to precision decimal places.norm.float(50.0, 15.0, 1.0, 100.0, 2) -> 52.37 |
norm.n(mean, stddev, min, max, minN, maxN)PRO | string | N unique normally-distributed values (N in [minN, maxN]) as a comma-separated string.norm.n(50.0, 10.0, 1, 100, 2, 4) -> 47,53,61 |
norm(mean, stddev, min, max)PRO | float64 | Normally-distributed random number in [min, max], rounded to 0 decimal places.norm(4, 1, 1, 5) -> 4 |
nurand_n(A, x, y, min, max) | string | Generates N unique NURand values (N in [min, max]) as a comma-separated string.nurand_n(255, 1, 100, 3, 5) -> 42,87,13,61 |
nurand(A, x, y) | int | TPC-C Non-Uniform Random: (((random(0,A) | random(x,y)) + C) / (y-x+1)) + x.nurand(255, 1, 100) -> 42 |
pareto.float(alpha, min, max, precision)PRO | float64 | Continuous Pareto random float in [min, max], rounded to precision decimal places. Note the argument shape differs from pareto.int: pareto.float follows the same (params..., min, max, precision) convention as every other .float.pareto.float(2.0, 0, 1000, 2) -> 3.47 |
pareto.int(alpha, max)PRO | int | Pareto-distributed random integer in [0, max]. Continuous power-law: lower values dominate. Higher alpha concentrates values near 0; alpha ≈ 1.16 gives the classic 80/20 rule.pareto.int(2.0, 999) -> 3 |
pareto.n(alpha, imax, minN, maxN)PRO | string | N unique Pareto-distributed values (N in [minN, maxN]) as a comma-separated string.pareto.n(2.0, 999, 3, 5) -> 1,3,8,22 |
poisson.int(lambda)PRO | int | Poisson-distributed random integer with mean lambda. Models count of events in a fixed interval (e.g. requests per second, errors per day).poisson.int(5.0) -> 4 |
poisson.n(lambda, minN, maxN)PRO | string | N unique Poisson-distributed values (N in [minN, maxN]) as a comma-separated string.poisson.n(5.0, 3, 5) -> 3,4,6,7 |
rwalk_f(group, start, drift, volatility, precision)PRO | float64 | Stateful random walk with precision. group names the walk; each worker starts it at start and accumulates steps: current += drift + volatility * N(0,1). Useful for simulating stock prices, sensor drift, or time series. Returns the cumulative value rounded to precision decimal places.rwalk_f('price', 100, 0.001, 0.02, 4) -> 100.3742 |
rwalk(group, start, drift, volatility)PRO | float64 | Stateful random walk. group names the walk; each worker starts it at start and accumulates steps: current += drift + volatility * N(0,1). Returns the cumulative value rounded to 0 decimal places.rwalk('price', 100, 0.001, 0.02) -> 100 |
uniform.float(min, max, precision) | float64 | Uniform random float in [min, max] rounded to precision decimal places.uniform.float(0.01, 999.99, 2) -> 347.82 |
uniform.int(min, max) | float64 | Uniform random float in [min, max].uniform.int(1, 100) -> 73.12 |
uniform.n(min, max, minN, maxN) | string | N unique uniform random values (N in [minN, maxN]) as a comma-separated string.uniform.n(1, 1000, 3, 5) -> 12,481,706,944 |
weibull.float(shape, scale, min, max, precision)PRO | float64 | Weibull-distributed random number in [min, max], rounded to precision decimal places. Models time-to-failure and reliability. Shape<1: decreasing failure rate, shape=1: exponential, shape>1: increasing failure rate.weibull.float(1.5, 100, 0, 500, 2) -> 87.34 |
weibull.n(shape, scale, min, max, minN, maxN)PRO | string | N unique Weibull-distributed values (N in [minN, maxN]) as a comma-separated string.weibull.n(1.5, 100, 0, 500, 3, 5) -> 31,87,102,164 |
weibull(shape, scale, min, max)PRO | float64 | Weibull-distributed random number in [min, max], rounded to 0 decimal places.weibull(1.5, 100, 0, 500) -> 87 |
zipf.int(s, v, max)PRO | int | Zipfian-distributed random integer in [0, max].zipf.int(2.0, 1.0, 999) -> 3 |
zipf.n(s, v, imax, minN, maxN)PRO | string | N unique Zipfian-distributed values (N in [minN, maxN]) as a comma-separated string.zipf.n(1.1, 1.0, 100000, 5, 15) -> 2,7,19,44,201,988 |
Every distribution namespace has an .n function whose final two arguments are always minN, maxN. A count is chosen uniformly at random in [minN, maxN] and that many distinct values are drawn. It is an error if minN < 1, if maxN < minN, or if that many distinct values can’t be found within 10,000 draws. Typical use is unique item IDs for multi-item order lines, e.g. TPC-C New-Order: zipf.n(1.1, 1.0, 100000, 5, 15).
There is deliberately no binomial.float, poisson.float or zipf.float - those distributions are integer-valued by definition. Use beta.float or gamma.float for a continuous skewed value.
Reference data#
| Function | Returns | Description |
|---|---|---|
beta.ref(name, alpha, beta)PRO | map | Returns a random row from a named dataset using Beta distribution. Alpha and beta shape which rows are favored. alpha=beta=1 is uniform; alpha<1, beta>1 favors later rows.beta.ref('products', 2, 5).name -> Widget |
binomial.ref(name, n, p)PRO | map | Returns a random row from a named dataset using Binomial distribution. n is the number of trials, p is success probability. Index centers around n*p.binomial.ref('products', 10, 0.3).name -> Gadget |
empirical.ref(name, samples)PRO | map | Returns a random row from a named dataset using an empirical CDF built from observed data. The sample values define the distribution shape that selects row indices.empirical.ref('products', [1, 2, 2, 3, 5]).name -> Widget |
exp.ref(name, rate)PRO | map | Returns a random row from a named dataset using exponential distribution. Lower indices are selected more frequently. rate controls decay speed.exp.ref('products', 1.5).name -> Widget |
gamma.ref(name, shape, rate)PRO | map | Returns a random row from a named dataset using Gamma distribution. Mean index is shape/rate. Useful for skewing access toward a particular region of the dataset.gamma.ref('products', 2, 1).name -> Widget |
lognorm.ref(name, mu, sigma)PRO | map | Returns a random row from a named dataset using log-normal distribution. Creates a right-skewed access pattern where early rows are favored.lognorm.ref('products', 0.0, 0.5).name -> Widget |
norm.ref(name, mean, stddev)PRO | map | Returns a random row from a named dataset using normal distribution. mean and stddev are expressed as fractions of the dataset length (e.g. 0.5 = middle, 0.2 = narrow spread).norm.ref('products', 0.5, 0.2).name -> Gadget |
pareto.ref(name, alpha)PRO | map | Returns a random row from a named dataset using Pareto distribution. Lower-indexed rows are strongly favored. Higher alpha concentrates access near the first row.pareto.ref('products', 2.0).name -> Widget |
poisson.ref(name, lambda)PRO | map | Returns a random row from a named dataset using Poisson distribution. Row index centers around lambda. Good for modeling event-count-based access patterns.poisson.ref('products', 3.0).name -> Gadget |
ref_cursor(query, size, col, repeat?) | cursor | Keyset-paginated cursor over a SQL query. Pages through results using WHERE col > last_value ORDER BY col LIMIT size, fetching one page at a time. Constant memory and constant query time per page - ideal for seeding from tables with millions of rows. Each page drives one batch of the parent query. Optional repeat count gives exact cardinality: each row is returned repeat times before advancing.ref_cursor('SELECT id FROM t ORDER BY id', 1000, 'id') -> pages of 1000 rowsref_cursor('SELECT id FROM t ORDER BY id', 1000, 'id', 3) -> each row repeated 3 times per page |
ref_diff(name) | map | Returns unique rows across multiple calls within the same query execution. Uses a swap-based index to avoid repeats.ref_diff('products').name -> Widget |
ref_each(query_or_dataset, repeat?) | [][]any or map | When given a SQL query string, executes it and returns all rows - each row becomes a separate arg set. When given a named reference dataset (unquoted), iterates sequentially through each row with same-row caching (like ref_same). Optional repeat count gives exact cardinality: each row is returned repeat times before advancing.ref_each('SELECT id FROM t') -> [[1], [2], [3]]ref_each(product_catalog).name -> Widgetref_each(customers, 3).id -> each customer ID repeated 3 times |
ref_n(name, field, min, max) | string | Picks N unique random rows (N in [min, max]) from a named dataset, extracts field from each, and returns a comma-separated string.ref_n('products', 'name', 2, 3) -> Widget,Gadget |
ref_perm(name) | map | Returns a random row on first call, then the same row for the entire lifetime of the worker.ref_perm('products').name -> Widget |
ref_same(name) | map | Returns a random row, but the same row is reused across all ref_same calls within a single query execution. Cleared between iterations.ref_same('products').name -> Widget |
ref_weighted(name, weights) | map | Picks a row from a named dataset using weighted random selection. Each weight is an integer controlling relative probability. The weights array must have one entry per row in the dataset.ref_weighted('data.cities', [556, 278, 139, 27]).name -> London |
ref(name) | map | Returns a random row from a named dataset (populated by an init query). Access fields with dot notation: ref('fetch_warehouses').w_id.ref('products').name -> Gadget |
weibull.ref(name, shape, scale)PRO | map | Returns a random row from a named dataset using Weibull distribution. Models failure-rate-based access patterns. Shape<1: early rows favored with decreasing rate, shape>1: increasing concentration.weibull.ref('products', 1.5, 100).name -> Widget |
weighted_sample_n(name, field, weightField, minN, maxN) | string | Picks N unique rows using weighted selection, returns a comma-separated string.weighted_sample_n('products', 'name', 'stock', 2, 3) -> Widget,Pen |
zipf.ref(name, s, v)PRO | map | Returns a random row from a named dataset using Zipfian distribution. The first row is the “hottest”, with frequency dropping off according to s (skew, > 1) and v (>= 1).zipf.ref('products', 2.0, 1.0).name -> Widget |
Results#
| Function | Returns | Description |
|---|---|---|
result() | map | Returns the first row of the current query’s SELECT result as a map. Only available in post_print (after query execution). Access columns with dot notation.result().total -> 10000 |
results() | []map | Returns all rows of the current query’s SELECT result as a slice of maps. Only available in post_print (after query execution). Use with expr-lang builtins like len(), map(), filter(), reduce() to aggregate across rows.len(results()) -> 5reduce(results(), #acc + #.balance, 0) -> 50000 |
Sequences#
| Function | Returns | Description |
|---|---|---|
beta.seq(name, alpha, beta)PRO | int | Beta-distributed value from a global sequence. Alpha and beta shape which indices are favored.beta.seq("order_id", 2, 5) -> 3 |
binomial.seq(name, n, p)PRO | int | Binomial-distributed value from a global sequence. Index centers around n*p.binomial.seq("order_id", 10, 0.3) -> 3 |
empirical.seq(name, samples)PRO | int | Empirical CDF-distributed value from a global sequence. The sample values define which indices are favored.empirical.seq("order_id", [1, 2, 2, 3, 5]) -> 4 |
exp.seq(name, rate)PRO | int | Exponentially-distributed value from a global sequence. Lower indices are selected more frequently.exp.seq("order_id", 0.5) -> 7 |
gamma.seq(name, shape, rate)PRO | int | Gamma-distributed value from a global sequence. Mean index is shape/rate.gamma.seq("order_id", 2, 1) -> 2 |
lognorm.seq(name, mu, sigma)PRO | int | Log-normally-distributed value from a global sequence.lognorm.seq("order_id", 2, 0.5) -> 8 |
norm.seq(name, mean, stddev)PRO | int | Normally-distributed value from a global sequence. mean and stddev are index positions (0-based).norm.seq("order_id", 500, 100) -> 487 |
pareto.seq(name, alpha)PRO | int | Pareto-distributed value from a global sequence. Lower indices (earlier values) are selected more frequently. Higher alpha increases concentration near the start.pareto.seq("order_id", 2.0) -> 3 |
poisson.seq(name, lambda)PRO | int | Poisson-distributed value from a global sequence. Index centers around lambda.poisson.seq("order_id", 5.0) -> 4 |
seq_alpha_global(name) | string | Shared auto-incrementing alpha sequence across all workers. Returns the next alpha value from a named sequence defined in the seq config section (requires length field).seq_alpha_global("sku_code") -> aaa |
seq_alpha(length) | string | Auto-incrementing alpha sequence per worker. Generates base-26 strings of the given length (e.g. aaa, aab, aac, …).seq_alpha(3) -> aaa |
seq_global(name) | int | Shared auto-incrementing sequence across all workers. Returns the next value from a named sequence defined in the seq config section. Thread-safe via atomic counters.seq_global("order_id") -> 1 |
seq(start, step) | int | Auto-incrementing sequence per worker. Returns start + counter * step.seq(1, 1) -> 1 |
uniform.seq(name) | int | Uniform random value from the already-generated values of a global sequence. Computes valid values from the sequence’s start, step, and current counter (no values stored in memory).uniform.seq("order_id") -> 42 |
weibull.seq(name, shape, scale)PRO | int | Weibull-distributed value from a global sequence. Models failure-rate-based index selection.weibull.seq("order_id", 1.5, 100) -> 7 |
zipf.seq(name, s, v)PRO | int | Zipfian-distributed value from a global sequence. Lower indices (earlier values) are selected more frequently. s (> 1) and v (>= 1) control the distribution shape.zipf.seq("order_id", 2.0, 1.0) -> 3 |
Set selection#
| Function | Returns | Description |
|---|---|---|
beta.set(values, alpha, beta)PRO | any | Picks an item from a set using Beta distribution.beta.set(['low', 'med', 'high'], 2, 5) -> low |
binomial.set(values, n, p)PRO | any | Picks an item from a set using Binomial distribution.binomial.set(['a', 'b', 'c', 'd', 'e'], 4, 0.3) -> b |
empirical.set(values, samples)PRO | any | Picks an item from a set using an empirical CDF built from observed data.empirical.set(['low', 'med', 'high'], [1, 1, 2, 5, 5]) -> med |
exp.set(values, rate)PRO | any | Picks an item from a set using exponential distribution.exp.set(['low', 'med', 'high'], 0.5) -> low |
gamma.set(values, shape, rate)PRO | any | Picks an item from a set using Gamma distribution.gamma.set(['low', 'med', 'high'], 2, 1) -> low |
lognorm.set(values, mu, sigma)PRO | any | Picks an item from a set using log-normal distribution.lognorm.set(['free', 'basic', 'pro'], 0.5, 0.5) -> free |
norm.set(values, mean, stddev)PRO | any | Picks an item from a set using normal distribution.norm.set([1, 2, 3, 4, 5], 2, 0.8) -> 3 |
pareto.set(values, alpha)PRO | any | Picks an item from a set using Pareto distribution. First items are strongly favored.pareto.set(['a', 'b', 'c'], 2.0) -> a |
poisson.set(values, lambda)PRO | any | Picks an item from a set using Poisson distribution.poisson.set(['a', 'b', 'c', 'd', 'e'], 2.0) -> c |
set(values, weights) | any | Picks a random item from a set. If weights are provided, weighted random selection is used; otherwise uniform.set(['a', 'b', 'c'], []) -> b |
weibull.set(values, shape, scale)PRO | any | Picks an item from a set using Weibull distribution.weibull.set(['low', 'med', 'high'], 1.5, 100) -> low |
zipf.set(values, s, v)PRO | any | Picks an item from a set using Zipfian distribution.zipf.set(['a', 'b', 'c'], 2.0, 1.0) -> a |
UUIDs & identifiers#
| Function | Returns | Description |
|---|---|---|
objectid() | string | Generates a MongoDB ObjectID (24-character hex string).objectid() -> 507f1f77bcf86cd799439011 |
ulid() | string | Generates a Universally Unique Lexicographically Sortable Identifier: 26 Crockford base32 characters (0123456789ABCDEFGHJKMNPQRSTVWXYZ - no I, L, O or U). A 48-bit millisecond timestamp followed by 80 random bits, so IDs generated in different milliseconds sort in creation order. Entropy comes from the seeded RNG, so the random suffix is reproducible under --rng-seed; the timestamp prefix is wall-clock derived.ulid() -> 01HQ3W5K8ZJXR7YQ2V4N6M8PBD |
uuid_v1() | string | Generates a Version 1 UUID (timestamp + node ID).uuid_v1() -> 6ba7b810-9dad-11d1-80b4-00c04fd430c8 |
uuid_v4() | string | Generates a Version 4 UUID (random).uuid_v4() -> 550e8400-e29b-41d4-a716-446655440000 |
uuid_v6() | string | Generates a Version 6 UUID (reordered timestamp).uuid_v6() -> 1ef21d2f-6ba7-6810-9dad-00c04fd430c8 |
uuid_v7() | string | Generates a Version 7 UUID (Unix timestamp + random, sortable).uuid_v7() -> 018ef4c9-7f3a-7b3c-8d1a-2b4c5d6e7f8a |
Vectors#
| Function | Returns | Description |
|---|---|---|
beta.vector(dims, clusters, spread, alpha, beta)PRO | string | Like vector but picks centroids using a Beta distribution. Alpha and beta shape which clusters are favored.beta.vector(32, 5, 0.1, 2, 5) |
binomial.vector(dims, clusters, spread, n, p)PRO | string | Like vector but picks centroids using a Binomial distribution. Cluster selection centers around n*p.binomial.vector(32, 5, 0.1, 4, 0.3) |
empirical.vector(dims, clusters, spread, samples)PRO | string | Like vector but picks centroids using an empirical CDF built from observed data.empirical.vector(32, 5, 0.1, [1, 2, 2, 3, 5]) |
exp.vector(dims, clusters, spread, rate)PRO | string | Like vector but picks centroids using an exponential distribution. Cluster 0 is the “hottest”, with frequency decaying according to rate.exp.vector(128, 5, 0.1, 0.5) |
gamma.vector(dims, clusters, spread, shape, rate)PRO | string | Like vector but picks centroids using a Gamma distribution. Mean cluster is shape/rate.gamma.vector(32, 5, 0.1, 2, 1) |
lognorm.vector(dims, clusters, spread, mu, sigma)PRO | string | Like vector but picks centroids using a log-normal distribution over cluster indices.lognorm.vector(128, 5, 0.1, 1.0, 0.5) |
norm.vector(dims, clusters, spread, mean, stddev)PRO | string | Like vector but picks centroids using a normal distribution over cluster indices. mean is the center cluster index, stddev controls spread.norm.vector(32, 5, 0.1, 2.0, 0.8) |
pareto.vector(dims, clusters, spread, alpha)PRO | string | Like vector but picks centroids using a Pareto distribution. Cluster 0 is the “hottest”, with continuous power-law falloff controlled by alpha.pareto.vector(32, 5, 0.1, 2.0) |
poisson.vector(dims, clusters, spread, lambda)PRO | string | Like vector but picks centroids using a Poisson distribution. Cluster selection centers around lambda.poisson.vector(32, 5, 0.1, 2.0) |
vector(dims, clusters, spread) | string | vector literal with uniform centroid selection. Generates clustered, unit-length vectors for realistic similarity search. dims is the number of dimensions, clusters is the number of cluster centroids, and spread controls intra-cluster noise (Gaussian σ).vector(4, 3, 0.1) -> [0.512340,-0.234567,0.678901,0.456789] |
weibull.vector(dims, clusters, spread, shape, scale)PRO | string | Like vector but picks centroids using a Weibull distribution.weibull.vector(32, 5, 0.1, 1.5, 100) |
zipf.vector(dims, clusters, spread, s, v)PRO | string | Like vector but picks centroids using a Zipfian distribution. Cluster 0 is the “hottest”, with frequency dropping off according to s (skew) and v (>= 1). Simulates real-world data where some categories have far more embeddings.zipf.vector(32, 5, 0.1, 2.0, 1.0) |
Choosing a Sequence Generator#
edg has three ways to generate sequential IDs. Picking the wrong one silently produces incorrect data, so choose carefully.
| Function | Scope | Resets? | IDs Unique Across Workers? | Use When |
|---|---|---|---|---|
iter() | Per batch query | Yes - resets to 1 at the start of each exec_batch / query_batch | N/A (single-worker seed) | Seeding tables with fixed-size ID ranges (1..N). Always starts at 1, unaffected by other queries. |
seq_alpha_global(name) | Global (all workers) | Never | Yes - atomic counter | Generating globally unique alpha codes (aaa, aab, …) across workers. Requires a seq config entry with length. |
seq_alpha(length) | Per worker | Never | No - each worker has its own counter | Generating monotonic alpha codes within a single worker’s run loop. |
seq_global(name) | Global (all workers) | Never | Yes - atomic counter | Generating globally unique IDs across concurrent workers in run. Requires a seq config entry. |
seq(start, step) | Per worker | Never | No - each worker has its own counter | Generating monotonic values within a single worker’s run loop (e.g. increasing timestamps, per-worker order numbers). |
Common mistakes#
Don’t use seq() across multiple seed queries.
seq(1, 1) is a single counter that never resets. If populate_accounts uses seq(1, 1) with count: 10, the counter reaches 10. A later populate_counters query using the same seq(1, 1) continues from 11, not 1. Use iter() instead - it resets per batch query.
seed {
populate_accounts(count: 10)
`INSERT INTO account (id) VALUES ($1)` (seq(1, 1))
populate_counters(count: 10)
`INSERT INTO counter (id) VALUES ($1)` (seq(1, 1))
}seed {
populate_accounts(count: 10)
`INSERT INTO account (id) VALUES ($1)` (iter())
populate_counters(count: 10)
`INSERT INTO counter (id) VALUES ($1)` (iter())
}Don’t use seq() when you need globally unique IDs.
With multiple workers, each worker’s seq(1, 1) produces 1, 2, 3, … independently - you’ll get duplicate IDs. Use seq_global instead.
Don’t use seq_global() for seed queries.
The counter never resets, so re-running deseed + seed produces new IDs each time. Use iter() for seeds and reserve seq_global for run workloads.
Function Lifecycle#
Several functions maintain state. Understanding when that state resets is important for getting correct results:
| Function | Scope | Resets |
|---|---|---|
arg(index) / arg('name') | Per-query | Returns the value of arg at index (or by name when using named args). Cleared before the next query. In batch queries, resets per row. |
beta.ref(name, alpha, beta) | None | Fresh random row on every call (Beta distribution) |
binomial.ref(name, n, p) | None | Fresh random row on every call (Binomial distribution) |
complete_array(tool, prompt, count) | Per-query | Makes one API call per unique (tool, prompt, count) tuple. The result ([]map) is memoized so multiple ref_each(local(...)).field accesses within a row share the same call. Not deferred - resolves immediately even in batch queries. |
complete(tool, prompt) | Per-batch | In exec/query (non-batch) queries, each unique (tool, prompt) pair makes one API call; same-row field accesses are memoized. In exec_batch/query_batch queries, all complete() calls are deferred - placeholder maps are inserted during arg evaluation, then all pending requests are resolved concurrently (up to 8 parallel) after the batch is generated. |
embed(text...) | Per-batch | In exec/query (non-batch) queries, each call makes a separate API request. In exec_batch/query_batch queries, all embed() calls within a batch are deferred - placeholders are inserted during arg evaluation, then all pending texts are resolved in a single API call (or multiple calls if --embed-max-batch is set). For example, a 100-row batch with --embed-max-batch 30 produces 4 API calls (30+30+30+10) instead of 100 individual calls. |
empirical.ref(name, samples) | None | Fresh random row on every call (empirical CDF distribution) |
exp.ref(name, rate) | None | Fresh random row on every call (exponential distribution) |
gamma.ref(name, shape, rate) | None | Fresh random row on every call (Gamma distribution) |
global_iter() | Global | Monotonic counter incremented once per RunIteration call by any worker. Never resets. Shared across all workers via atomic int64. Use for time-series seasonality and data drift. |
iter() | Per-query | Returns 1 for the first row, 2 for the second, etc. Resets to 0 at the start of each batch query. |
lognorm.ref(name, mu, sigma) | None | Fresh random row on every call (log-normal distribution) |
markov(group, states, matrix) | Per-worker | Each worker maintains its own Markov chain state per group. Starts at state 0, transitions on each call using the probability matrix. Never resets. |
mvnorm(group, index, means, stddevs, correlations) | Per-row | Generates all dimensions on first call within a row and caches them. Subsequent calls for different indices within the same row return correlated values from the same draw. Cache clears between rows. |
norm.ref(name, mean, stddev) | None | Fresh random row on every call (normal distribution) |
nurand(A, x, y) | Per-worker | The TPC-C constant C is generated once per worker per A value and stays fixed for the worker’s lifetime. |
pareto.ref(name, alpha) | None | Fresh random row on every call (Pareto distribution) |
poisson.ref(name, lambda) | None | Fresh random row on every call (Poisson distribution) |
ref_diff(name) | Per-query | Returns a unique row on each call within a query (no repeats). Index resets before the next query. |
ref_perm(name) | Per-worker | Picks a row on first call and returns that same row for the entire lifetime of the worker. Never resets. |
ref_same(name) | Per-query | Picks a row on first call within a query; all subsequent ref_same calls for the same dataset within that query return the same row. Cleared before the next query. |
ref_weighted(name, weights) | None | Fresh weighted random row on every call |
ref(name) | None | Fresh random row on every call |
result() / results() | Per-query | Returns the last query’s result rows. Only available in post_print expressions. Set after each type: query execution; cleared after each type: exec. |
rwalk(group, start, drift, volatility) /rwalk_f(group, start, drift, volatility, precision) | Per-worker | Each worker accumulates steps independently per group. Current value starts at start and drifts with each call. Never resets. |
seq_global(name) | Global | Single counter shared across all workers via atomic increment. Values are globally unique. Configured in the seq config section. |
seq(start, step) | Per-worker | Counter starts at 0 for each worker and increments on every call. Two workers both calling seq(1, 1) will produce the same sequence independently – values are not globally unique. |
uniform.seq | Global | Pick from already-generated sequence values using the named distribution. The valid value set grows as seq_global advances the counter. No values are stored in memory. |
uniq_across(pool, expression [, ...]) | Global (per pool) | Tracks seen values across all queries sharing the same pool name. Never resets - persists for the lifetime of the environment. Use when values must be unique across multiple seed queries. |
uniq(expression [, ...]) | Per-query | Tracks seen values (or composite tuples) across all rows within a query. Composite calls are cached per-row so multiple arg positions share the same tuple. Resets between queries. |
vector / zipf.vector / pareto.vector /norm.vector / beta.vector / gamma.vector /weibull.vector / poisson.vector /binomial.vector / empirical.vector /exp.vector / lognorm.vector | Per-worker | Cluster centroids are generated on first call (keyed by dims+clusters) and reused for the worker’s lifetime. Each call picks a centroid using the named distribution and adds noise. |
weibull.ref(name, shape, scale) | None | Fresh random row on every call (Weibull distribution) |
zipf.ref(name, s, v) | None | Fresh random row on every call (Zipfian distribution) |
zipf.seq / pareto.seq / norm.seq /exp.seq / lognorm.seq / beta.seq /gamma.seq / weibull.seq / poisson.seq /binomial.seq / empirical.seq | Global | Same as uniform.seq but with shaped distributions. |