属性間制約
「属性Aの値がXならば、属性Bは必須である」というような属性間の制約の設定方法について記載します。
属性間制約とは
「属性Aの値がXならば、属性Bは必須である」というような、複数の属性間の制約を「属性間制約」と呼びます。
同じラベルに属する複数の属性間で制約を設けることができます。
属性間制約の設定の流れ
属性間制約はアノテーション仕様画面 では設定できません。CLIなどを利用して設定する必要があります。具体的には、以下のような手順になります。
- 属性間制約をJSONで記述する。
- annofabcli annotation_specs add_attribute_restrictionコマンドを実行して、属性間制約を設定する。
- 属性間制約が正しく設定されていることを確認する
属性間制約をJSONで記述する
以下のようなJSONで属性制約を記述します。以下のJSONは、「属性IDがAである属性の値がXならば、属性IDがBである属性の値は空文字列でない(必須である)」という制約を表しています。
{
"additional_data_definition_id": "B",
"condition": {
"_type": "Imply",
"premise": {
"additional_data_definition_id": "A",
"condition": {
"_type": "Equals",
"value": "X"
}
},
"condition": {
"_type": "NotEquals",
"value": ""
}
}
}condition.premiseに、「もし~ならば」という前提条件を記載して、condition.conditionに満たすべき制約を記載します。JSONの詳細は、getAnnotationSpecs APIのレスポンスを参照してください。AnnotationSpecsV3スキーマ配下のrestrictionsのAdditionalDataRestrictionに詳細が記載されています。
annofabapi.util.attribute_restrictionsを利用して制約を記述する
annofabapi.util.attribute_restrictionsを利用して制約を記述する上記のJSONを人間が直接記述する際は、以下の課題があります。
- 属性名でなく属性IDを記述する必要がある。属性IDはデフォルトでUUIDなので、JSONを見ただけではどのような制約なのかが分からない
- 属性の種類によって使用できる制約が異なるため、間違えて使用できない制約(トラッキングID属性での
Matches(正規表現に一致する)など)を設定してしまう。
annofabapi.util.attribute_restrictions モジュールを利用すると、上記の課題を解決できます。以下のようなPythonのコードで、属性間制約を記述できます。
- 属性名で制約を定義できる
- 属性の種類によって、利用できる制約がメソッドで定義されている
>>> import annofabapi
>>> import json
>>> from annofabapi.util.attribute_restrictions import AttributeFactory
>>> service = annofabapi.build()
>>> annotation_specs, _ = service.api.get_annotation_specs("prj1", query_params={"v": "3"})
>>> fac = AttributeFactory(annotation_specs)
# 「'occluded'チェックボックスがONならば、'note'テキストボックスは空ではない」という制約
>>> restriction = fac.checkbox(attribute_name="occluded").checked().imply(fac.string_textbox(attribute_name="note").is_not_empty())
>>> print(json.dumps(restriction.to_dict())
{
"additional_data_definition_id": "9b05648d-1e16-4ea2-ab79-48907f5eed00",
"condition": {
"_type": "Imply",
"premise": {
"additional_data_definition_id": "2517f635-2269-4142-8ef4-16312b4cc9f7",
"condition": {
"_type": "Equals",
"value": "true"
}
},
"condition": {
"_type": "NotEquals",
"value": ""
}
}
}
属性間制約の例
よくある属性間制約の例を記載します。
- チェックボックスAがONならば、テキストボックスXは入力できない(disabled)
fac.checkbox(attribute_name="A").checked().imply(fac.string_textbox(attribute_name="X").disabled()) - チェックボックスAがONならば、テキストボックスXは空文字である
fac.checkbox(attribute_name="A").checked().imply(fac.string_textbox(attribute_name="X").is_not_empty()) - チェックボックスAがONならば、ドロップダウン(またはラジオボタン)Xは選択肢Tを選択できない
fac.checkbox(attribute_name="A").checked().imply(fac.selection(attribute_name="X").not_has_choice(choice_name="T")) - チェックボックスAがONかつチェックボックスBがONならば、テキストボックスXは空文字でない(必須)
fac.checkbox(attribute_name="A").checked().imply(fac.checkbox(attribute_name="B").imply(fac.string_textbox(attribute_name="X").is_not_empty()))
annofab-cli-llm を使って自然言語から制約を記述する
annofabcli-llm parse_attribute_restrictionコマンドを使うことで、自然言語で記載されたアノテーションルールなどから、属性間制約のJSONを生成できます。
$ annofabcli-llm parse_attribute_restriction \
--project_id $PROJECT_ID \
--restriction_text 属性occludedがチェックされているとき属性notは必須
--output_format annofab_json
[
{
"additional_data_definition_id": "attr_note",
"condition": {
"_type": "Imply",
"premise": {
"additional_data_definition_id": "attr_occluded",
"condition": {
"_type": "Equals",
"value": "true"
}
},
"condition": {
"_type": "NotEquals",
"value": ""
}
}
}
]
annofab-cliを使って属性間制約を設定する
annofabcli annotation_specs add_attribute_restrictionコマンドを実行して、属性間制約を設定します。
$ cat restriction.json
{
"additional_data_definition_id": "9b05648d-1e16-4ea2-ab79-48907f5eed00",
"condition": {
"_type": "Imply",
"premise": {
"additional_data_definition_id": "2517f635-2269-4142-8ef4-16312b4cc9f7",
"condition": {
"_type": "Equals",
"value": "true"
}
},
"condition": {
"_type": "NotEquals",
"value": ""
}
}
}
$ annofabcli annotation_specs add_attribute_restriction --project_id prj1 --restriction_json file://restriction.json
制約を確認する
CLIで確認する
属性間の制約はアノテーション仕様画面では確認できないので、annofab-cliで確認します。annotation_specs list_attribute_restrictionコマンドを実行すると、自然言語で表現された制約が出力されます。
$ annofabcli annotation_specs list_attribute_restriction --project_id prj1 > out.txt
$ cat out.txt
'B' DOES NOT EQUAL '' IF 'A' EQUALS 'X'
アノテーションエディタ画面で確認する
アノテーションエディタ画面で実際に操作して、制約が正しいかを確認します。
今回の例だと、「ドロップダウン属性Aの値がX AND ドロップダウン属性Bの値が空欄」のときのみ、「制約に合うように修正してください」というエラーメッセージが表示されます。
Updated 2 days ago
