請求書と領収書は同じ入り口を共有します。 2 つの構造の混合を避けるにはどうすればよいでしょうか?
1 つのインターフェイスで請求書と領収書の両方を受け取り、「すべてのフィールドがオプション」の大きなオブジェクトを簡単に作成できます。このようなオブジェクトには何でも保持できますが、正確に何を受け取ったのかを知るのは困難です。 2 つの別個のコントラクトを保持し、明示的なタイプ フィールドを使用してそのうちの 1 つを選択する方が明確です。
請求書と領収書は処理のために同じインターフェイスに置かれることがよくありますが、「すべてのフィールドがオプション」の広範なオブジェクトのみを使用して受信した場合は、あらゆる入力に対応できますが、どのような種類の文書を受信したかはわかりません。この記事は、ドキュメント受信インターフェイスを設計したり、JSON スキーマ検証ルールを保守したりする必要がある開発者およびビジネス担当者を対象としています。これを読むと、2 つの独立したコントラクトを保持し、明示的な型フィールドを持つ 1 つを選択し、分岐の競合と不明な型を処理する方法がわかります。
この記事の例では、合成サンプルを使用して処理方法を示します。コードは隔離された環境でサンプルを使用してチェックされていますが、これはすべての実際のファイルや製品のパフォーマンスを保証するものではありません。重要な書類を処理する前に、原本を保管し、本文の境界と許容事項に従って確認してください。
請求書と領収書の入り口が共用になっている場合はどうすればよいですか?一文の結論
同じポータルから 2 つのドキュメントを受信する場合、すべてを保持できる広範なオブジェクトを使用するよりも、2 つの個別の契約を保持し、必要な kind フィールドを使用してそのうちの 1 つを選択する方が明確です。
| あなたの状況 | 推奨される実践方法 | 理由 |
|---|---|---|
| 請求書と領収書を受信するには同じインターフェイスが必要です | 必須の種類フィールドで選択された 2 つの個別の契約を保持します。 | すべてのフィールドがオプションの大きなオブジェクトは何でも保持できますが、何を受信するかを説明するのは困難です。 |
| oneOf でブランチを整理する | 各ブランチは const を使用して種類を固定します | oneOf では、正確に 1 つのブランチが一致する必要があります。分岐フィールドが重複すると、正当な入力が失敗します。 |
| 入力不足のタイプまたはフィールドの競合 | 競合するフィールドとソースを示す明確なエラー メッセージを返す | 「一致しない」と表示されるだけでは問題の特定には役立ちません |
| 分類子はドキュメントの種類を区別できません | 不明ステータスを保持し、分類される独立キューに入る | ブランチをランダムに選択すると、偽の「成功」しか生み出されません。 |
| 構造検証に合格しました | 分類が正しいという意味ではなく、文書が本物であるという意味でもありません。 | 分類の信頼性、構造検証、およびビジネスの信頼性は 3 つの異なるレベルです |
なぜ幅広いオブジェクトを使用できないのですか?
すべてのフィールドをオプションにするリスク
インターフェイスが請求書と領収書の両方を受け入れる場合、「すべてのフィールドがオプション」の大きなオブジェクトを簡単に作成できます。このようなオブジェクトは実際にさまざまな入力を受け取ることができますが、次のようなコストがかかります。
- 構造からはどの文書を受信したかを判断することは不可能です。
・2つの書類の必須項目と任意項目が混在しており、検証ルールがあいまいになってきている。
- エラーが発生した場合、入力が期待どおりに行われていない箇所を正確に説明することは困難です。
2 つの別個のコントラクトを保持し、明示的なタイプ フィールドを使用してそのうちの 1 つを選択する方が明確です。
oneOf はどれか 1 つだけではありません
分岐が重なっていると、正当な入力が失敗します。
oneOf では、入力が 1 つのブランチに正確に一致する必要があります。両方のブランチが同時に合格した場合、全体の検証は失敗します。
ブランチに含まれるオプションのフィールドが少数である場合、それらは大幅に重複する可能性があります。現時点では、法的な入力は検証に合格できません。
kind と const を使用して重複を排除します
必須の kind フィールドと const の固定値を使用すると、ブランチ間の明確な境界を確立し、そのような重複を事前に排除できます。
組み合わせルールの詳細についてはJSONスキーマの組み合わせルールを参照してください。
実行可能なオフロード プロトコル
from jsonschema import Draft202012Validator
def branch(kind, identity):
return {
"type": "object", "additionalProperties": False,
"required": ["kind", identity],
"properties": {"kind": {"const": kind},
identity: {"type": "string", "minLength": 1}}
}
schema = {"oneOf": [branch("invoice", "invoice_number"),
branch("receipt", "receipt_number")]}
v = Draft202012Validator(schema)
valid = lambda x: not list(v.iter_errors(x))
assert valid({"kind": "invoice", "invoice_number": "I-1"})
assert valid({"kind": "receipt", "receipt_number": "R-1"})
assert not valid({"kind": "invoice", "receipt_number": "R-1"})
assert not valid({"kind": "receipt", "receipt_number": ""})
assert not valid({"kind": "invoice", "invoice_number": "I-1",
"receipt_number": "R-1"})
assert not valid({"kind": "unknown"})
これは簡略化されたレコードの例であり、実際の請求書の完全なフィールド モデルではありません。このコードは、分岐の選択と冗長フィールドの拒否を示しています。税率、ヘッダー、金額は個別に定義する必要があります。
ビジネスでフィールドの追加が許可されている場合は、すべての制約を静かにキャンセルするのではなく、これらのフィールドの名前空間を明示する必要があります。
エラー メッセージに「一致しません」とだけ表示しないでください。
「不一致」のみが表示され、ユーザーも保守者も問題がどこにあるのかわかりません。次の表に、いくつかの一般的な入力機能と対応するフィードバック方法を示します。
| 入力特徴 | 実際の疑問 | 提案とフィードバック |
|---|---|---|
| 種類がありません | プロトコルを選択できません | 書類の種類を入力してください |
| タイプが数値フィールドと競合します | 2つの構造が混在している | 競合するフィールドとソースを表示する |
| 数値の空の文字列 | キーは存在しますが、値がありません | 番号が振られたエリアを振り返る |
| 不明なタイプ | 現在の契約の対象外 | 独立した待機列に入る |
不定型にもアウトレットが必要です
分類子が請求書と領収書を区別できない場合は、「成功」を推測するためにランダムな分岐を選択するのではなく、不明な状態のままにする必要があります。
ここには 3 つの異なるレベルがあり、個別に検討する必要があります。
- 分類の信頼度: システムが文書タイプを判断する際の自信度。
- 構造検証: 入力が選択した契約に準拠しているかどうか。
- ビジネスの信頼性: 文書自体が本物で有効であるかどうか。
構造検証に合格しても、分類が正しいことは証明できませんし、文書が本物であることも証明できません。
文書タイプは翻訳プロセスでも保持される必要があります
同じフィールドでも、ドキュメントごとに異なる用語を使用する必要がある場合があります。OmniDocの用語とバイリンガルのレビュー ワークフローを使用する場合、納品リストとともに文書タイプを提供すると、レビュー担当者が数値と金額のコンテキストを理解するのに役立ちます。
広範な JSON オブジェクトによってこれらの違いが消失しないようにしてください。
📊 コアの比較
| 練習する | 書類の種類を明確にしてもらえますか? | 枝が重なった場合の動作 | 未知の型の処理 |
|---|---|---|---|
| すべてのフィールドがオプションの広範なオブジェクト | 私が受け取ったものを説明するのは難しいです。 | 適用されません。フィールド間の分岐境界はありません | さまざまな物体に飲み込まれやすく、検出が困難 |
| 2つの独立した契約+必要な種類 | 種類フィールドによる明示的な選択 | const を使用して値を固定し、重複を減らします | 不明ステータスを保持し、分類されるキューに入る |
🎯 どの方法があなたに適していますか?
請求書と領収書の両方を受け取る必要がある場合
2 つの別個の契約を保持し、kind を必須フィールドにします。
ブランチフィールドが多く重複している場合
複数のブランチに同時に一致する正当な入力を避けるために、各ブランチの kind を const で修正します。
システムで追加フィールドが許可されている場合
まず追加フィールドの名前空間を明確にしてから、制約を緩和する方法を決定します。
分類子に十分な自信がない場合
ステータスを不明のままにし、ドキュメントをキューに送信して並べ替えます。ブランチを強制的に選択しないでください。
❓ よくある質問 (FAQ)
1. すべてのフィールドがオプションのオブジェクトを使用してみてはいかがでしょうか?
このようなオブジェクトには何でも保持できますが、正確に何を受け取ったのかを知るのは困難です。
2. oneOf が法的入力に失敗するのはなぜですか?
oneOf では、正確に 1 つのブランチと一致する必要があります。両方のブランチが同時に合格した場合、全体の検証は失敗します。この状況は、ブランチ フィールドが多く重複する場合に発生しやすくなります。
3. フィールドの追加を許可する場合、何に注意する必要がありますか?
追加フィールドの名前空間は、すべての制約を黙ってキャンセルするのではなく、明示的にする必要があります。
4. 分類子が文書タイプを判断できない場合はどうすればよいですか?
不明な状態を維持し、分類される独立したキューに入ります。成功するためにランダムにブランチを選択しないでください。
5. 構造検証に合格した場合、その文書は本物であることを意味しますか?
できません。分類の信頼性、構造検証、およびビジネスの信頼性は 3 つの異なるレベルです。構造を渡すことは、文書が本物であることを証明することはできません。
📝 概要
請求書と領収書を同じエントリに配置する場合は、入力された文書の種類が明確に見えるように、2 つの別個の契約書を保持し、必須の kind フィールドでそれらを選択します。分岐検証、エラー フィードバック、不明なタイプの出口も一緒に設計する必要があります。


