倉庫についての主要な概念
FlexSimの倉庫ツールとは
FlexSimには、倉庫施設のモデリングを行うことができる強力なツールセットがあります。これらの倉庫ツールは、倉庫やストレージの複雑な設計のさまざまな面を分析するのに役立ちます。これらのツールを使用すると、データ分析のために現実的かつ多角的なモデルを作成できます。
ただし、複雑な倉庫モデルを作成する前に、できるだけ早期にモデルのコンセプトを簡素化することをお勧めします。倉庫モデルには多くの側面があるため、すぐに複雑になる可能性があります。そのため、モデルで解決する問いや、モデルから収集する具体的なデータを最初に決めておくことをお勧めします。
倉庫シミュレーションの最初に具体的な問いを設定することは重要です。それによってモデル設計の方向性が決まるためです。答えに結び付かない細部については、モデリング処理から除外してください。問いの検討に必須ではない要素については、抽象化するか、経験に基づく仮定を行うことで、余分な作業を省くことができます。
不完全な問いや回答の難しい問いの例を示します。
- スループットを最適化するにはどうすればよいか?
- オーダーの処理時間を改善するにはどうすればよいか?
これらの問いはあまりにオープンエンドであいまいです。何が「最適」かを判断する十分な指標が定義されていません。こうしたタイプの問いは、一般に、解析の難しい非常に複雑なモデルにつながります。これらのあいまいな指標に何らかの要素が影響を与える可能性があるためです。
一方、良い問いとは、提案した変更と、比較対象となるパフォーマンス指標の両方が含まれています。良い問いの例を示します。
- 提案したこのラッキングシステムは、必要なピッキングスループットに対応できるか?
- これら2つのレイアウトのうち、オーダーから出荷までの処理時間を最短にするものはどちらか?
- 施設には、予測在庫レベルを処理できる十分なラッキングがあるか?
最も重要なのは、モデルから抽出する必要のあるデータを考えることです。モデルから取得する必要のあるデータを決定した後で、倉庫モデルの構築について、いくつかの分野を検討します。それは、倉庫のレイアウト設定、在庫の監視、製品の取得です。
詳細については、プロジェクトの目標と範囲の概念に関する詳しい記事を参照してください。
倉庫のレイアウト設定
倉庫シミュレーションを設計するとき、決定すべき重要な要素の1つが倉庫自体のレイアウトです。アイテムをどこに、どのように保管するか、オペレーターとトランスポーターはどこにアクセスできなければならないか、アイテムのアドレス指定とゾーン指定をどのように行うか、などを検討する必要があります。
ストレージシステム
FlexSimでモデルにラックオブジェクトを初めてドラッグすると、[ツール]フォルダに新しいオブジェクトが作成されます。画面の左側のパネルにある[ツールボックス]タブをクリックすると、ストレージシステムオブジェクトがリストされています。ストレージシステムは、ラッキングオブジェクトと倉庫オブジェクトのロジックを1つのハブに一元化したものです。ラベル、ラックのビジュアル化、アドレス方式、トリガーはすべて、ストレージシステムオブジェクトから作成し、コントロールできます。このドキュメントの以降のセクションでは、ストレージシステムツールについて説明しますが、ストレージシステムとその機能全般については、ストレージシステムに関するドキュメントを参照してください。
ベイ、レベル、スロット、および[寸法]タブ
ラックの構造は、ベイ、レベル、スロットから成るマトリクス形式のグリッド、つまりテーブルで設定します。3Dビューでラックオブジェクトをクリックすると、[プロパティ]ウィンドウでプロパティが開きます。[ストレージオブジェクト]セクションで[寸法を編集]ボタンをクリックして、以下のテーブルを表示します(クリックしたラックのタイプによって、内容が多少異なる場合がありますが、基本的なシステムはすべてのラックタイプに共通です)。
この図から、ラックのベイ、レベル、スロットの構造がわかります。ベイは横軸に沿った領域、レベルは縦軸に沿ったスペース、スロットはベイとレベルで囲まれたスペース、つまり「セル」をさらに分割したものです。詳細については、ストレージオブジェクトの[寸法]タブに関する参照ドキュメントを参照してください。
ベイ進行とレベル進行
ラックのピックフェースとは、ラックのうち、オペレーターとトランスポーターがアイテムをロードする側を指します。一般的な倉庫環境の場合、ピッカーは、ラックの棚からアイテムを取得します。これが「ピックフェース」の語源であり、ピッキングを行うラックの面を意味します。論理的な目的で、ラックのピックフェースをラックの「前」側と見なすことができます。そこから、ベイとレベルのカウント方法がわかります。デフォルト設定では、ベイのカウントは1から始まり、左から右へ、1回に1ベイずつ進みます。レベルのカウントも同様に、下から始まり、上に進みます。このカウントの方向をベイ/レベル進行といい、1回に進むベイの数をベイ幅といいます。
[アドレスマッピング]セクションでは、ラックのベイとレベルのカウント方法だけでなく、ラックのアドレス方式も変更できます。このドキュメントでは、アドレス方式について後で詳しく説明します。ベイ進行とレベル進行、ベイ幅とレベル幅の詳細については、ストレージオブジェクトに関する参照ドキュメントを参照してください。
場所とアイテムの割り当てと検索
倉庫のレイアウトを決定したら、次に、倉庫に保管するアイテムにどのように場所を割り当てるかを決定します。それには複数の方法があります。オーダーテーブル、つまり製品のアドレス情報を記した在庫のスプレッドシートのようなものがある場合、[ストレージシステムのプロパティ]ウィンドウでアドレス方式を設定できます。あるいは、Storage.systemコマンドを使用して、アイテムのスロットを決定するルールまたはクエリを作成することもできます。
アドレス方式
SKUとアドレス情報を記した在庫情報のテーブル(オーダーテーブルや入庫テーブルなど)がすでにある場合、ツールボックスのストレージシステムツールからアドレス方式を実装できます。そうしたテーブルがまだない場合、ラックオブジェクトをモデルにドラッグすると、ツールボックスのストレージシステムオブジェクトが初期化されます。モデルでラックを作成すると、モデル内のストレージシステムオブジェクトが自動的に初期化されます。[ツールボックス]タブを選択し、ツールにリストされたストレージシステムをダブルクリックすると、[ストレージシステムのプロパティ]ウィンドウが開きます。このウィンドウが開いたら、[アドレス方式]タブを選択します。アドレス方式を作成するための情報や詳細が表示されます。
この[アドレス方式]タブには、プロジェクトに複数のアドレス方式を作成し、保守することができる複数のフィールドがあります。一番上のフィールドには、現在選択されているテーマが表示されており、このフィールドの横には、アドレス方式の作成、コピー、削除、並べ替えを行うボタンが複数表示されています。一般に、倉庫で使用するアドレス方式は1つだけです。ただし、アドレス方式は、モデルロジックに必要なだけ作成することができます。たとえば、シミュレートする施設に複数の建物があり、それぞれの建物でまったく異なるアドレス方式を使用する場合、この方法は便利です。
次の行は、選択したアドレス方式の書き方の例です。アドレス方式を独自に定義する前に、アドレスの各部分の構成要素について理解しておくことが重要です。アドレスの分類は、最も大きいものから順に、ゾーン、通路、ベイ、レベル、スロットです。[ゾーンID]は、倉庫の場所を示す最も大きな分類です。通常は、ラックのグループを含む倉庫内のエリアを指します。[通路ID]は、ラックのグループが属す通路を指します。[ベイID]は、ラックのベイを指します。その後に[レベルID]が続きます。[スロットID]は、アイテムを割り当てる具体的な場所を指します。デフォルトの方式を選択した場合、[例]フィールドにはZ-A-1-1-1と表示されます。この文字列は、このアドレス方式のアドレス文字列がどのように表されるかを示すサンプルです。この場合、最初の文字はゾーン(Zone)を示します。ハイフンに続く2番目の文字は通路(Aisle)を示します。その後、ベイ、レベル、スロットと続きます。区切り文字としてハイフンが使用されます。この文字列は、あるスロットの場所をアドレスで検索するときに検索パラメータに渡される情報の例を示しています。
詳細については、ストレージシステムのドキュメントの「[アドレス方式]タブ」を参照してください。
アドレス方式を作成または選択した後で、ラックにこの方式を割り当てることができます。ラックオブジェクトをクリックして右側にプロパティを開き、[アドレスマッピング]セクションの対応するドロップダウンメニューからアドレス方式を選択できます。方式を選択した後で、ゾーンIDまたは通路IDを割り当てることができます。
[オブジェクト]タブ
ストレージシステムに接続されているすべてのラックオブジェクトの概要を表示するには、[ストレージシステムのプロパティ]ウィンドウの[オブジェクト]タブをクリックする方法もあります。このタブでは、ラックの表示と並べ替え、ゾーンIDや通路IDの編集を行うことができます。ベイ、レベル、スロットの開始、幅、進行も編集できます。デフォルトでは、ベイのみが表示されます。ただし、このウィンドウの上部にあるオプションボタンをクリックし、表示されるチェックボックスを使用すると、編集するラックオブジェクトのプロパティを表示または非表示にすることができます。
FlexScriptを使用したアドレスによるスロットの取得
アドレス方式を設定すると、スロットを取得してそのスロットにアイテムを割り当てるまでの処理をいくつかの簡単なFlexScriptコマンドで行うことができます。
FlexSimには、ストレージオブジェクトツールと倉庫ツールを取り扱うために、FlexScriptコマンドで使用するStorageというクラスがあります。Storage.Systemクラスとその関数および属性の詳細については、Storage.System FlexScript APIを参照してください。
Storage.system.getSlot()メソッドを使用すると、渡したアドレスに基づいてスロットを取得できます。このメソッドは文字列を要求し、文字列の文字を、モデルで設定されたアドレス方式に突き合せます。アドレスがアドレス方式に一致する場合、メソッドは該当するスロットを特定し、そのスロットを返します。そこから、スロットをアイテムに割り当てることができます。
次の処理フローは、スロットを取得し、そのスロットをトークンのラベルに割り当て、取得したスロットをアイテムに割り当てる方法を示した例です。
[ラベルを割り当て]アクティビティを使用すると、トークンにラベルを割り当てることができます。ラベルの値に関するピックリストオプションから値を選択すると、[倉庫]メニューから[アドレスでストレージスロットを取得]という項目を選択できます。[ラベル]の[値]フィールドにgetSlot()コマンドが含まれているのがわかります。デフォルトでは、パラメータ値としてフィラーラベルが入力されます。このパラメータ値の部分にアドレス文字列、またはアドレス文字列を伴うラベルを入力することができます。
スロットを割り当てた後で、スロットが取得されたかどうかを確認することをお勧めします。そのためには、[決定]アクティビティを使用します。条件付き決定タイプを使用し、条件としてtoken.Slot(または任意のスロットラベル)を指定します。これで、スロットが取得されたかどうがわかります。
最後に、取得したスロットをアイテムに割り当てる必要があります。アイテムにスロットが割り当てられている場合、ラックのロジックはアイテムの配置方法と配置先を判別できます。アイテムにスロットを割り当てるには、[カスタムコード]アクティビティを使用します。[カスタムコード]アクティビティのピックリストオプションに表示される[コントロール]セクションの[倉庫]サブセクションから[スロットを割り当て(直接)]オプションを選択します。アイテムとスロットを定義する2つのフィールドが表示されます。
処理フロー以外に、ストレージスロットの取得と割り当てを行うスクリプトを作成することもできます。次のスクリプトは、スロットを取得し、そのスロットをアイテムに割り当てる方法を示したFlexScriptの例です。
Storage.Slot slot = Storage.system.getSlot("1-A-1-3-2");
if (slot && slot.hasSpace(item)) {
Storage.Item storageItem = Storage.Item(item);
storageItem.assignedSlot = slot;
}
token.Slot = slot;
このスクリプトでは、まずSystem.Slotクラスの「slot」変数を宣言します。次に、この変数に値を割り当てるためにStorage.system.getSlot()関数を使用します。その際、システムのアドレス方式に一致する文字列を渡します。関数は、アドレスに基づいてスロットを探し、値として返します。
コードの次の行では、スロットが取得されたかどうかを確認し、次にslot.hasSpace()関数を使用して、アイテム用のスペースがあるかどうかを確認します。ある場合は、アイテムにスロットを割り当てます。アイテムにスロットを割り当てる処理は重要なステップです。スロットを割り当てられたアイテムは、スロットのラックに移されると、割り当てられた該当スロットに自動的に配置されるためです。
スロットのラベルの設定
スロットとスロット値を割り当てるには、ラベルを使用する方法もあります。ストレージシステムオブジェクトのプロパティの最初のタブ、[スロットラベル]をクリックします。デフォルトでは、このウィンドウは空白ですが、緑色の「+」記号をクリックすると、ストレージシステムのすべてのスロットにラベルを追加できます。たとえば、スロットにタイプラベルをアタッチする場合、この方法が早道です。ここで新しいラベルを作成すると、そのラベルのオプションを指定するフィールドがいくつか表示されます。最初のフィールドはラベル名です。次のフィールドでは、モデルのカラーパレット群から特定のカラーパレットを選択します(詳細については、カラーパレットに関する参照ドキュメントを参照してください)。[インデックス付き]チェックボックスでは、ラベルにインデックスを付けるかどうかを選択できます(インデックス付与の詳細については、スロットラベルに関する参照ドキュメントを参照してください)。最後のフィールドでは、ラベルのデフォルト値の有無を指定します。
ラベルによるスロットの検索と割り当て
ラックとストレージシステムの設定時にラベルを指定した場合、Storageクラスのある関数を使用して、アイテムに割り当てるスロットを検索することができます。この方法は、アドレス方式を使用してスロットの取得と割り当てを行う機能とよく似ています。Storageクラスには、アドレス方式の代わりにラベルのクエリを使用してスロットを検索する関数があります。それはStorage.system.findSlot()メソッドです。このメソッドにSQL構文のクエリを文字列として渡すと、アイテムに割り当てることができるスロットが戻ります。
この処理は、アドレス方式を使用してスロットを取得したときとほぼ同じ方法で処理フローに設定することができます。アドレス方式の場合と同様に、[ラベルを割り当て]アクティビティを使用し、ラベルに値を割り当てる際にピックリストオプションを使用します。[倉庫]セクションを選択し、[ストレージスロットの検索]オプションを選択します。
クエリを入力できるGUIと、クエリ内のオブジェクトを指定できるフィールドが表示されます。たとえば、ストレージシステムを使用してスロットをタイプで検索する場合、クエリは次のようになります。
WHERE Type IS $1.Type
次に、Typeラベルを持つトークンを$1と指定します。
このクエリは、タイプラベルがトークンのタイプラベルと一致するストレージスロットを返します。アドレス方式の場合と同様に、次に[決定]アクティビティを使用してスロットが取得されたかどうかを判定し、その次に[カスタムコード]アクティビティを使用して、取得したスロットをアイテムに割り当てることができます。
また、アドレス方式でgetSlot()メソッドを使用したように、FlexScriptのfindSlot()メソッドを使用できます。スクリプトとクエリは次のようになります。
Storage.Slot slot = Storage.system.findSlot("WHERE Type = $1.Type AND slot.hasSpace($1) ORDER BY RAND()", 0, item);
if (slot) {
Storage.Item storageItem = Storage.Item(token.Item);
storageItem.assignedSlot = slot;
}
token.Slot = slot;
このスクリプトでは、取得するスロットを変数「slot」として宣言します。次に、この変数に値を割り当てるためにStorage.system.findSlot()関数を使用し、クエリを渡します。関数の最初のパラメータは、クエリ文字列です。このクエリは、まず、タイプラベルがアイテムのタイプラベルと一致するスロットをストレージシステムから検索し、次にそのスロットにアイテム用のスペースがあるかどうかを確認し、ある場合は、そのスロットを返されたスロットとしてランダムに並べ替えます。関数の次のパラメータ0はFlexScriptで予約されており、0にする必要があります。最後のパラメータは、クエリの$1が示す値です。この後にオプションパラメータがある場合は、$2、$3、$4などが示す値です。
コードの次の行は、この関数によってスロットが戻ったかどうかを確認し、戻った場合は、取得されたこのスロットを保管対象のアイテムに割り当てます。
スロットの検索処理フローアクティビティ
上記2つの例を行うもう一つのアプローチとしては、[スロットの検索]アクティビティを使用してスロットを取得し、そのスロットへアイテムを割り当てる方法があります。
[スロットの検索]アクティビティを使用することで、複数クエリを定義してスロット、使用アドレス、ラベル、プロパティなどを検索することができます。スロットがすぐに発見できない場合、[スロットの検索]アクティビティのトークンは維持されてストレージシステムの終了時をリッスンします。アイテムがストレージシステムを出る場合、一致するスロットを発見できるまでクエリの再評価が行われます。
[スロットの検索]アクティビティは上記の例に記載されているステップを、すべて1つのアクティビティ内で実行します。
次の処理フローは、スロットを検索し、アイテムに割り当ててストレージオブジェクトに移動する方法について、一例を示します。
アイテムの検索と取得
Storage.system.findSlot()メソッドでスロットを検索してアイテムに割り当てることができるように、Storage.system.findItem()を使用してストレージシステムからアイテムを検索することもできます。スロットを検索する関数と同様に、この関数もパラメータとして文字列クエリを要求しますが、Storage.system.findSlot()がStorage.Slotへの参照を返すのに対して、Storage.system.findItem()はStorage.Slot.Itemへの参照を返します。ストレージシステムのアイテムを発見すると、そのアイテムを取得するロジックを実行できるようになります。
スロットを検索するために処理フローを作成したように、アイテムを検索するために同様のフローを作成できます。まず、スロットを検索したときと同じように、[ラベルを割り当て]アクティビティを作成します。[ラベルを割り当て]アクティビティの[値]フィールドのピックリストオプションを使用して、[倉庫]セクションを選択し、[ストレージスロットのアイテムを検索]項目を選択します。
クエリを作成するフィールドと、クエリ内の語を指定するフィールドが表示されます。たとえば、アイテムをタイプラベルで検索するクエリを作成する場合、クエリは次のようになります。
WHERE Type = $1.Type
「$1」は、この場合、処理フローのトークンを指定するために使用されています。このクエリは、タイプラベルがトークンのタイプラベルと一致する全アイテムをストレージシステムから検索します。このクエリに場所や距離などを追加して、選択内容を絞り込むこともできます。
同様に、このコマンドをFlexScriptで使用することもできます。Storage.system.finditem()関数を使用するスクリプトの例を示します。
Storage.Slot.Item slotItem = Storage.system.findItem("WHERE Type = $1 ORDER BY RAND()", 0, token.Type);
token.Item = 0;
if (slotItem) {
slotItem.storageItem.assignedSlot = 0;
token.Item = slotItem.item;
}
このコード例では、まず、Storage.Slot.Itemクラスのインスタンスを示す「slotItem」という変数を宣言します。これをStorage.system.findItem()と呼び、クエリを実行して、(存在する場合は)一致するスロットアイテムを返します。
コードの次の行では、スロットアイテムが戻ったかどうかを評価し、戻った場合は、トークンのアイテムラベルが付けられた、スロットアイテムの関連アイテムオブジェクトを格納します。そのアイテムラベルから、見つかったアイテムの参照がわかるため、アイテムを取得するためのロジックや、適用する他のロジックを実行することができます。
アイテムの検索処理フローアクティビティ
上記の例を行うもう一つのアプローチとしては、[アイテムの検索]アクティビティを使用してアイテムを取得し、そのアイテムをアウトバウンドとしてマークする方法があります。
[アイテムの検索]アクティビティを使用することで、複数クエリを定義してアイテム、使用アドレス、ラベル、プロパティなどを検索することができます。アイテムがすぐに発見できない場合、[アイテムの検索]アクティビティのトークンは維持されてストレージシステムのエントリ時をリッスンします。新規アイテムがストレージシステムに入る場合、一致するアイテムを発見できるまでクエリの再評価が行われます。
[アイテムの検索]アクティビティは上記の例に記載されているステップを、すべて1つのアクティビティ内で実行します。
次の処理フローは、アイテムを検索し、アウトバウンドとしてマーク(割り当てスロットを解除)してそのアイテムをストレージオブジェクトの外に移動する方法について、一例を示します。