分散モード

配分ポリシーを作成する場合、次のいずれかの配分モードを指定して、ワーカーにジョブを配分するときに使用する戦略を定義します。

ラウンド ロビン モード

ジョブは、利用可能な各ワーカーが順番にジョブを受け取れるように、循環的に配分されます。

最長アイドル モード

ジョブは、最も使用率が低いワーカーから配布されます。 順位が同じ場合は、より長い時間利用可能となっているワーカーを選択します。 使用率は、次のアルゴリズムにより、Load Ratio のように計算されます。

負荷率 = ワーカーに割り当てられるすべてのジョブによって消費される能力の集計/ ワーカーの合計能力

chat ジョブはワーカーごとに 1 能力を消費するように構成されていると仮定します。 新しいチャット ジョブが Job Router のキューに登録されており、次のワーカーたちがジョブの受け取りが可能です。

Worker A:
Capacity = 5
ConsumedScore = 3 (Currently handling 3 chats)
LoadRatio = 3 / 5 = 0.6
LastAvailable: 5 mins ago

Worker B:
Capacity = 4
ConsumedScore = 3 (Currently handling 3 chats)
LoadRatio = 3 / 4 = 0.75
LastAvailable: 3 min ago

Worker C:
Capacity = 5
ConsumedScore = 3 (Currently handling 3 chats)
LoadRatio = 3 / 5 = 0.6
LastAvailable: 7 min ago

Worker D:
Capacity = 3
ConsumedScore = 0 (Currently idle)
LoadRatio = 0 / 4 = 0
LastAvailable: 2 min ago

Workers would be matched in order: D, C, A, B

Worker D は最も低い負荷率 (0) であるため、Worker D に最初にジョブがオファーされます。 Worker A と C は、同じ負荷率 (0.6) です。 ただし、Worker C は Worker A (5 分前から) よりも長い時間 (7 分前から) 利用可能となっているため、Worker C が Worker A の前に照合されます。最後に、Worker B は最も高い負荷率 (0.75) であるため、最後に照合します。

最適ワーカー モード

そのジョブを最も良く処理できるワーカーが最初に選ばれます。 ワーカーをランク付けするロジックはカスタマイズ可能で、式や Azure 関数を使用して、指定した Scoring Rule で 2 人のワーカーを比較します。 例を参照してください

Scoring Rule が指定されていない場合、この配分モードでは、代わりに既定のスコアリング メソッドが使用されます。これは、ジョブのラベルおよびセレクターとワーカーのラベルとの適合率に基づいてワーカーを評価します。 このアルゴリズムの概要を次に示します。

既定のラベル照合

ジョブのラベルに基づいてスコアを計算するために、対応するジョブのラベルと適合するすべてのワーカー ラベルごとに Match Score を 1 ずつ増やし、ジョブのラベルの合計数で除算します。 つまり、適合するラベルが多いほど、ワーカーの Match Score は高くなります。 最後の Match Score は常に 0 から 1 の間の値になります。

ジョブ 1:

{
  "labels": {
    { "language": "english" },
    { "department": "sales" }
  }
}

Worker A:

{
  "labels": {
    { "language": "english" },
    { "department": "sales" }
  }
}

Worker B:

{
  "labels": {
    { "language": "english" }
  }
}

Worker C:

{
  "labels": {
    { "language": "english" },
    { "department": "support" }
  }
}

計算:

Worker A's match score = 1 (for matching english language label) + 1 (for matching department sales label) / 2 (total number of labels) = 1
Worker B's match score = 1 (for matching english language label) / 2 (total number of labels) = 0.5
Worker C's match score = 1 (for matching english language label) / 2 (total number of labels) = 0.5

Worker A が最初に照合されます。 次に、マッチ スコアが同順位のため、Worker B か Worker C の、より長い時間、利用可能だった方が照合されます。

既定のワーカー セレクター照合

ジョブにワーカー セレクターも含まれている場合、ワーカー セレクターの LabelOperator に基づいて Match Score を計算します。

等価/不等価 ラベル演算子

ワーカー セレクターに LabelOperatorEqualまたはNotEqual がある場合、上記の Label Matching と同様の方法で、そのワーカー セレクターに適合するジョブ ラベルごとにスコアを 1 ずつ増やします。

ジョブ 2:

{
  "workerSelectors": [
    { "key": "department", "labelOperator": "equals", "value": "billing" },
    { "key": "segment", "labelOperator": "notEquals", "department": "vip" }
  ]
}

Worker D:

{
  "labels": {
    { "department": "billing" },
    { "segment": "vip" }
  }
}

Worker E:

{
  "labels": {
    { "department": "billing" }
  }
}

Worker F:

{
  "labels": {
    { "department": "sales" },
    { "segment": "new" }
  }
}

計算:

Worker D's match score = 1 (for matching department selector) / 2 (total number of worker selectors) = 0.5
Worker E's match score = 1 (for matching department selector) + 1 (for matching segment not equal to vip) / 2 (total number of worker selectors) = 1
Worker F's match score = 1 (for segment not equal to vip) / 2 (total number of labels) = 0.5

Worker E が最初に照合されます。 次に、マッチ スコアが同順位のため、Worker D か Worker F の、より長い時間、利用可能だった方が照合されます。

その他のラベル演算子

大きさの比較を行う演算子 (GreaterThan/GreaterThanEqual/LessThan/LessThanEqual) を使用するワーカー セレクターの場合は、ロジスティック関数を使用して計算された量ずつ、ワーカーの Match Score を増やします (図 1 を参照)。 この計算は、ワーカーのラベル値がワーカー セレクターの値をどれだけ超えているか、ワーカー セレクターの値を超えていない場合は差がより小さいかに基づいています。 したがって、ワーカーの値がワーカー セレクター値を超えているほど、その程度が大きい分だけ、ワーカーのスコアが高くなります。

Diagram that shows logistic function.

図 1. ロジスティック関数

GreaterThan 演算子または GreaterThanEqual 演算子には、次の関数が使用されます。

MatchScore(x) = 1 / (1 + e^(-x)) where x = (labelValue - selectorValue) / selectorValue

LessThan 演算子または LessThanEqual 演算子には、次の関数が使用されます。

MatchScore(x) = 1 / (1 + e^(-x)) where x = (selectorValue - labelValue) / selectorValue

ジョブ 3:

{
  "workerSelectors": [
    { "key": "language", "operator": "equals", "value": "french" },
    { "key": "sales", "operator": "greaterThanEqual", "value": 10 },
    { "key": "cost", "operator": "lessThanEqual", "value": 10 }
  ]
}

Worker G:

{
  "labels": {
    { "language": "french" },
    { "sales": 10 },
    { "cost": 10 }
  }
}

Worker H:

{
  "labels": {
    { "language": "french" },
    { "sales": 15 },
    { "cost": 10 }
  }
}

Worker I:

{
  "labels": {
    { "language": "french" },
    { "sales": 10 },
    { "cost": 9 }
  }
}

計算:

Worker G's match score = (1 + 1 / (1 + e^-((10 - 10) / 10)) + 1 / (1 + e^-((10 - 10) / 10))) / 3 = 0.667
Worker H's match score = (1 + 1 / (1 + e^-((15 - 10) / 10)) + 1 / (1 + e^-((10 - 10) / 10))) / 3 = 0.707
Worker I's match score = (1 + 1 / (1 + e^-((10 - 10) / 10)) + 1 / (1 + e^-((10 - 9) / 10))) / 3 = 0.675

3 人のワーカーはすべて、ジョブのワーカー セレクターに適合しており、このジョブを作業する資格があります。 ただし、Worker H は "sales" ワーカー セレクター値より、 5 高いことがわかります。 一方、Worker I は cost ワーカー セレクター値を 1 だけ超えています。 Worker G は、どのワーカー セレクター値もまったく超えていません。 したがって、Worker H を最初に照合し、次に Worker I、最後に Worker G を照合します。