Skip to main content

GroupDiversity

Type: Goal or Constraint

Require each scope item to hold objects from at least, or at most, N distinct groups of a partition. For example, make each host run tasks from at least 2 different jobs, or from at most 2 jobs.

Parameters

ParameterTypeRequiredDefaultDescription
namestringNo""Descriptive name for logging/debugging.
scopestringYes-The scope the bound applies to (e.g. "host").
partitionstringYes-Partition whose groups are counted (e.g. "job").
dimensionstringYes-A group counts as present in a scope item when its utilization for this dimension is positive. Use the object-count dimension (<object>_count) to count any group with at least one object there.
limitLimitNoglobalLimit 1The threshold N. Set globalLimit to apply one N to every scope item, or scopeItemLimits to set a different N per scope item.
boundGroupDiversityBoundNoMINWhether N is a lower (MIN) or upper (MAX) bound on distinct groups (see Bound).
filterFilterNoall scope itemsWhich scope items the spec applies to.

Example

An example use: place tasks on hosts so each host runs a mix of jobs. There are 8 tasks across 4 jobs (2 each), all initially unassigned. A job partition groups the tasks, and a GroupDiversity goal asks host0 to run at least 2 jobs and host1 at least 3.

solver.setObjectName("task");
solver.setContainerName("host");

solver.setAssignment(std::map<std::string, std::vector<std::string>>{
{"unassigned",
{"task0", "task1", "task2", "task3", "task4", "task5", "task6", "task7"}},
{"host0", {}},
{"host1", {}},
});

// Group the tasks by job (2 tasks per job).
solver.addPartition(
"job",
std::map<std::string, std::string>{
{"task0", "job0"}, {"task1", "job0"},
{"task2", "job1"}, {"task3", "job1"},
{"task4", "job2"}, {"task5", "job2"},
{"task6", "job3"}, {"task7", "job3"}});

// Each host must run at least 2 jobs, except host1 (>= 3).
GroupDiversitySpec spec;
spec.scope() = "host";
spec.partition() = "job";
spec.dimension() = "task_count";
spec.limit()->globalLimit() = 2;
spec.limit()->scopeItemLimits() = {{"host1", 3}};
solver.addGoal(spec);

Rebalancer pulls in tasks from distinct jobs until each host meets its threshold: host0 ends with tasks from 2 jobs and host1 from 3. Tasks it does not need stay unassigned.

Bound

bound selects whether N is a lower or upper bound on the number of distinct groups in each scope item:

BoundMeaning
MIN (default)Each scope item must hold objects from at least N distinct groups (spread for diversity).
MAXEach scope item may hold objects from at most N distinct groups (limit how many groups share a scope item).

MIN is the diversity use case above. MAX is the reverse: for example, with scope = "host", partition = "job", and a MAX limit of 2, Rebalancer keeps each host to tasks from at most 2 jobs.

Goal vs. constraint

As a constraint, the bound must hold for every scope item. If the initial assignment already satisfies it, so does the final one. If a scope item starts out violating it, the general constraint policy takes over: under the default policy Rebalancer fixes the violation as best it can.

As a goal, the bound is not required to hold; instead the solver minimizes how far the scope items are from it---the number of groups each scope item is short of (MIN) or over (MAX), summed across all scope items.

Source