إن مسطرة الأحداث (وتسمى مسطرة في بقية المستند للإيجاز) هي مكتبة Java تسمح بمطابقة القواعد مع الأحداث . الحدث عبارة عن قائمة من الحقول، والتي يمكن تقديمها كأزواج اسم/قيمة أو ككائن JSON. تقوم القاعدة بربط أسماء حقول الأحداث بقوائم القيم المحتملة. هناك سببان لاستخدام المسطرة:
محتويات:
من الأسهل الشرح بالقدوة.
الحدث هو كائن JSON. هنا مثال:
{
"version" : "0" ,
"id" : "ddddd4-aaaa-7777-4444-345dd43cc333" ,
"detail-type" : "EC2 Instance State-change Notification" ,
"source" : "aws.ec2" ,
"account" : "012345679012" ,
"time" : "2017-10-02T16:24:49Z" ,
"region" : "us-east-1" ,
"resources" : [
"arn:aws:ec2:us-east-1:123456789012:instance/i-000000aaaaaa00000"
] ,
"detail" : {
"c-count" : 5 ,
"d-count" : 3 ,
"x-limit" : 301.8 ,
"source-ip" : "10.0.0.33" ,
"instance-id" : "i-000000aaaaaa00000" ,
"state" : "running"
}
}
يمكنك أيضًا رؤية هذا كمجموعة من أزواج الاسم/القيمة. للإيجاز، نقدم عينة فقط. يحتوي المسطرة على واجهات برمجة التطبيقات لتوفير الأحداث في نموذج JSON وكأزواج اسم/قيمة:
+--------------+------------------------------------------+
| name | value |
|--------------|------------------------------------------|
| source | "aws.ec2" |
| detail-type | "EC2 Instance State-change Notification" |
| detail.state | "running" |
+--------------+------------------------------------------+
قد يتم توفير الأحداث في نموذج JSON في شكل سلسلة JSON خام، أو Jackson JsonNode التي تم تحليلها.
تتطابق جميع القواعد الموجودة في هذا القسم مع نموذج الحدث أعلاه:
{
"detail-type" : [ "EC2 Instance State-change Notification" ] ,
"resources" : [ "arn:aws:ec2:us-east-1:123456789012:instance/i-000000aaaaaa00000" ] ,
"detail" : {
"state" : [ "initializing" , "running" ]
}
}
سيؤدي هذا إلى مطابقة أي حدث مع القيم المتوفرة لقيم resource
detail-type
و detail.state
، مع تجاهل أي حقول أخرى في الحدث. سيكون متطابقًا أيضًا إذا كانت قيمة detail.state
قد تم "initializing"
.
يتم توفير القيم في القواعد دائمًا كمصفوفات، وتتطابق إذا كانت القيمة في الحدث إحدى القيم المتوفرة في المصفوفة. يوضح المرجع إلى resources
أنه إذا كانت القيمة في الحدث عبارة عن مصفوفة أيضًا، فإن القاعدة تتطابق إذا كان التقاطع بين مصفوفة الحدث ومصفوفة القاعدة غير فارغ.
{
"time" : [ { "prefix" : "2017-10-02" } ]
}
تعمل مطابقات البادئة فقط على الحقول ذات قيمة السلسلة.
{
"source" : [ { "prefix" : { "equals-ignore-case" : "EC2" } } ]
}
تعمل مطابقات حالة الأحرف يساوي تجاهل البادئة فقط على الحقول ذات قيمة السلسلة.
{
"source" : [ { "suffix" : "ec2" } ]
}
تعمل مطابقات اللاحقة فقط على الحقول ذات قيمة السلسلة.
{
"source" : [ { "suffix" : { "equals-ignore-case" : "EC2" } } ]
}
تعمل مطابقات اللاحقة يساوي تجاهل حالة الأحرف فقط على الحقول ذات قيمة السلسلة.
{
"source" : [ { "equals-ignore-case" : "EC2" } ]
}
تعمل مطابقات حالة التساوي والتجاهل فقط على الحقول ذات قيمة السلسلة.
{
"source" : [ { "wildcard" : "Simple*Service" } ]
}
تعمل مطابقات أحرف البدل فقط على الحقول ذات قيمة السلسلة. يمكن أن تحتوي القيمة الواحدة على صفر أو العديد من أحرف البدل، ولكن لا يُسمح بأحرف البدل المتتالية. لمطابقة حرف العلامة النجمية على وجه التحديد، يمكن تخطي حرف البدل باستخدام شرطة مائلة عكسية. يمثل خطان مائلان عكسيان متتاليان (أي خط مائل عكسي تم تجاوزه بشرطة مائلة عكسية) حرف الخط المائل العكسي الفعلي. غير مسموح بشرطة مائلة عكسية للهروب من أي حرف بخلاف العلامة النجمية أو الشرطة المائلة العكسية.
أي شيء ما عدا المطابقة يفعل ما يقوله الاسم: يطابق أي شيء باستثناء ما هو منصوص عليه في القاعدة.
يعمل أي شيء باستثناء سلسلة واحدة وقيم أو قوائم رقمية، والتي يجب أن تحتوي على سلاسل كاملة أو أرقام كاملة. ويمكن أيضًا تطبيقه على بادئة أو لاحقة أو مطابقة حالة يساوي تجاهل سلسلة أو قائمة سلاسل.
مفردة أي شيء ولكن (سلسلة، ثم رقمية):
{
"detail" : {
"state" : [ { "anything-but" : "initializing" } ]
}
}
{
"detail" : {
"x-limit" : [ { "anything-but" : 123 } ]
}
}
أي شيء ما عدا القائمة (سلاسل):
{
"detail" : {
"state" : [ { "anything-but" : [ "stopped" , "overloaded" ] } ]
}
}
أي شيء باستثناء القائمة (الأرقام):
{
"detail" : {
"x-limit" : [ { "anything-but" : [ 100 , 200 , 300 ] } ]
}
}
أي شيء باستثناء البادئة:
{
"detail" : {
"state" : [ { "anything-but" : { "prefix" : "init" } } ]
}
}
أي شيء باستثناء قائمة البادئات (السلاسل):
{
"detail" : {
"state" : [ { "anything-but" : { "prefix" : [ "init" , "error" ] } } ]
}
}
أي شيء ما عدا اللاحقة:
{
"detail" : {
"instance-id" : [ { "anything-but" : { "suffix" : "1234" } } ]
}
}
أي شيء باستثناء قائمة اللاحقة (السلاسل):
{
"detail" : {
"instance-id" : [ { "anything-but" : { "suffix" : [ "1234" , "6789" ] } } ]
}
}
أي شيء ولكن تجاهل الحالة:
{
"detail" : {
"state" : [ { "anything-but" : { "equals-ignore-case" : "Stopped" } } ]
}
}
قائمة أي شيء ولكن تجاهل الحالة (سلاسل):
{
"detail" : {
"state" : [ { "anything-but" : { "equals-ignore-case" : [ "Stopped" , "OverLoaded" ] } } ]
}
}
أي شيء ما عدا حرف البدل:
{
"detail" : {
"state" : [ { "anything-but" : { "wildcard" : "*/bin/*.jar" } } ]
}
}
أي شيء باستثناء قائمة أحرف البدل (سلاسل):
{
"detail" : {
"state" : [ { "anything-but" : { "wildcard" : [ "*/bin/*.jar" , "*/bin/*.class" ] } } ]
}
}
{
"detail" : {
"c-count" : [ { "numeric" : [ ">" , 0 , "<=" , 5 ] } ] ,
"d-count" : [ { "numeric" : [ "<" , 10 ] } ] ,
"x-limit" : [ { "numeric" : [ "=" , 3.018e2 ] } ]
}
}
أعلاه، توضح المراجع إلى c-count
و d-count
و x-limit
المطابقة الرقمية، وتعمل فقط مع القيم التي هي أرقام JSON. تدعم المطابقة الرقمية نفس الدقة والنطاق مثل البدائي double
لـ Java والذي يطبق معيار IEEE 754 binary64
.
{
"detail" : {
"source-ip" : [ { "cidr" : "10.0.0.0/24" } ]
}
}
يعمل هذا أيضًا مع عناوين IPv6.
توجد أعمال مطابقة لوجود أو عدم وجود حقل في حدث JSON.
سوف تتطابق القاعدة أدناه مع أي حدث يحتوي على حقل Detail.c-count.
{
"detail" : {
"c-count" : [ { "exists" : true } ]
}
}
سوف تتطابق القاعدة أدناه مع أي حدث لا يحتوي على حقل التفاصيل.c-count.
{
"detail" : {
"c-count" : [ { "exists" : false } ]
}
}
ملاحظة: التطابق Exists
يعمل فقط على العقد الطرفية. لا يعمل على العقد المتوسطة.
على سبيل المثال، المثال أعلاه exists : false
سيطابق الحدث أدناه:
{
"detail-type" : [ "EC2 Instance State-change Notification" ] ,
"resources" : [ "arn:aws:ec2:us-east-1:123456789012:instance/i-000000aaaaaa00000" ] ,
"detail" : {
"state" : [ "initializing" , "running" ]
}
}
ولكنه سيطابق أيضًا الحدث أدناه لأن c-count
ليس عقدة طرفية:
{
"detail-type" : [ "EC2 Instance State-change Notification" ] ,
"resources" : [ "arn:aws:ec2:us-east-1:123456789012:instance/i-000000aaaaaa00000" ] ,
"detail" : {
"state" : [ "initializing" , "running" ]
"c-count" : {
"c1" : 100
}
}
}
{
"time" : [ { "prefix" : "2017-10-02" } ] ,
"detail" : {
"state" : [ { "anything-but" : "initializing" } ] ,
"c-count" : [ { "numeric" : [ ">" , 0 , "<=" , 5 ] } ] ,
"d-count" : [ { "numeric" : [ "<" , 10 ] } ] ,
"x-limit" : [ { "anything-but" : [ 100 , 200 , 300 ] } ] ,
"source-ip" : [ { "cidr" : "10.0.0.0/8" } ]
}
}
كما توضح الأمثلة أعلاه، تعتبر المسطرة قاعدة متطابقة إذا كانت جميع الحقول المسماة في القاعدة متطابقة، كما أنها تعتبر حقلًا مطابقًا إذا كانت أي من قيم الحقول المتوفرة متطابقة، أي أن المسطرة قد طبقت منطق "و" إلى كافة الحقول بشكل افتراضي بدون "و" البدائية مطلوبة .
هناك طريقتان للوصول إلى تأثيرات "أو":
"$or" البدائي للسماح للعميل بوصف العلاقة "Or" مباشرة بين الحقول في القاعدة.
يتعرف المسطرة على العلاقة "أو" فقط عندما تستوفي القاعدة جميع الشروط التالية:
/src/main/software/amazon/event/ruler/Constants.java#L38
على سبيل المثال، لن يتم تحليل القاعدة أدناه على أنها " أو" لأن "الرقمية" و"البادئة" هما كلمات رئيسية محجوزة للمسطرة. {
"$or": [ {"numeric" : 123}, {"prefix": "abc"} ]
}
بخلاف ذلك، يتعامل المسطرة مع "$or" كاسم ملف عادي مثل السلسلة الأخرى في القاعدة.
عادي "أو":
// Effect of "source" && ("metricName" || "namespace")
{
"source" : [ "aws.cloudwatch" ] ,
"$or" : [
{ "metricName" : [ "CPUUtilization" , "ReadLatency" ] } ,
{ "namespace" : [ "AWS/EC2" , "AWS/ES" ] }
]
}
الموازي "أو":
// Effect of ("metricName" || "namespace") && ("detail.source" || "detail.detail-type")
{
"$or" : [
{ "metricName" : [ "CPUUtilization" , "ReadLatency" ] } ,
{ "namespace" : [ "AWS/EC2" , "AWS/ES" ] }
] ,
"detail" : {
"$or" : [
{ "source" : [ "aws.cloudwatch" ] } ,
{ "detail-type" : [ "CloudWatch Alarm State Change" ] }
]
}
}
"أو" لديه "و" في الداخل
// Effect of ("source" && ("metricName" || ("metricType && "namespace") || "scope"))
{
"source" : [ "aws.cloudwatch" ] ,
"$or" : [
{ "metricName" : [ "CPUUtilization" , "ReadLatency" ] } ,
{
"metricType" : [ "MetricType" ] ,
"namespace" : [ "AWS/EC2" , "AWS/ES" ]
} ,
{ "scope" : [ "Service" ] }
]
}
متداخلة "أو" و"و"
// Effect of ("source" && ("metricName" || ("metricType && "namespace" && ("metricId" || "spaceId")) || "scope"))
{
"source" : [ "aws.cloudwatch" ] ,
"$or" : [
{ "metricName" : [ "CPUUtilization" , "ReadLatency" ] } ,
{
"metricType" : [ "MetricType" ] ,
"namespace" : [ "AWS/EC2" , "AWS/ES" ] ,
"$or" : [
{ "metricId" : [ 1234 ] } ,
{ "spaceId" : [ 1000 ] }
]
} ,
{ "scope" : [ "Service" ] }
]
}
من المحتمل أن يكون "$or" مستخدمًا بالفعل كمفتاح عادي في بعض التطبيقات (على الرغم من أنه نادر على الأرجح). في هذه الحالات، يبذل تطبيق Ruler قصارى جهده للحفاظ على التوافق مع الإصدارات السابقة. فقط عند توفر الشروط الثلاثة المذكورة أعلاه، ستغير المسطرة سلوكها لأنها تفترض أن قاعدتك كانت تريد حقًا OR وتم تكوينها بشكل خاطئ حتى اليوم. على سبيل المثال، ستستمر القاعدة أدناه في العمل كقاعدة عادية مع التعامل مع "$or" كاسم حقل عادي في القاعدة والحدث:
{
"source" : [ "aws.cloudwatch" ] ,
"$or" : {
"metricType" : [ "MetricType" ] ,
"namespace" : [ "AWS/EC2" , "AWS/ES" ]
}
}
ارجع إلى /src/test/data/normalRulesWithOrWording.json
لمزيد من الأمثلة على أن "$or" تم تحليله كاسم حقل عادي بواسطة Ruler.
لا ينبغي تصميم الكلمة الأساسية "$or" كعلاقة بدائية "Or" كحقل عادي في كل من الأحداث والقواعد. يدعم المسطرة القواعد القديمة حيث يتم تحليل "$or" كاسم حقل عادي للحفاظ على التوافق مع الإصدارات السابقة وإعطاء الوقت للفريق لترحيل استخدامهم القديم "$or" بعيدًا عن الأحداث والقواعد كاسم ملف عادي. الاستخدام المختلط لـ "$or" باعتباره "Or" بدائيًا، و"$or" كاسم حقل عادي لا يتم دعمه عمدًا بواسطة Ruler لتجنب حدوث الغموض المحرج للغاية في "$or".
هناك طريقتان لاستخدام المسطرة. يمكنك تجميع قواعد متعددة في "جهاز"، ثم استخدام أي من أسلوب rulesForEvent()
أو أساليب rulesForJSONEvent()
للتحقق من القواعد التي تطابق أي حدث. تمت مناقشة الفرق بين هاتين الطريقتين أدناه. ستستخدم هذه المناقشة rulesForEvent()
بشكل عام باستثناء الحالات التي يكون فيها الاختلاف مهمًا.
وبدلاً من ذلك، يمكنك استخدام طريقة منطقية ثابتة واحدة لتحديد ما إذا كان حدث فردي يطابق قاعدة معينة.
توجد طريقة منطقية ثابتة واحدة Ruler.matchesRule(event, rule)
- يتم توفير كلا الوسيطتين كسلاسل JSON.
ملاحظة: هناك طريقة أخرى مهملة تسمى Ruler.matches(event, rule)
والتي لا ينبغي استخدامها لأن نتائجها غير متوافقة مع rulesForJSONEvent()
و rulesForEvent()
. راجع الوثائق الموجودة على Ruler.matches(event, rule)
للحصول على التفاصيل.
وقت المطابقة لا يعتمد على عدد القواعد. هذا هو الخيار الأفضل إذا كان لديك العديد من القواعد المحتملة التي تريد الاختيار منها، وخاصة إذا كان لديك طريقة لتخزين الجهاز المترجم.
يتأثر وقت المطابقة بدرجة عدم الحتمية الناتجة عن قواعد أحرف البدل وأي شيء ما عدا أحرف البدل. يتدهور الأداء نظرًا لتزايد عدد بادئات قاعدة أحرف البدل التي تتطابق مع حدث أسوأ حالة نظريًا. لتجنب ذلك، يجب أن تتجنب قواعد أحرف البدل المتعلقة بنفس حقل الحدث البادئات الشائعة التي تؤدي إلى حرف البدل الأول الخاص بها. إذا كانت هناك حاجة إلى بادئة شائعة، فاستخدم الحد الأدنى لعدد أحرف البدل وحدد تسلسلات الأحرف المتكررة التي تحدث بعد حرف البدل. يمكن استخدام MachineComplexityEvaluator لتقييم الجهاز وتحديد درجة عدم الحتمية أو "التعقيد" (أي عدد بادئات قاعدة أحرف البدل التي تتطابق مع حدث أسوأ حالة نظريًا). فيما يلي بعض نقاط البيانات التي توضح انخفاضًا نموذجيًا في الأداء لزيادة درجات التعقيد.
من المهم الحد من تعقيد الماكينة لحماية تطبيقك. هناك استراتيجيتان مختلفتان على الأقل للحد من تعقيد الآلة. أيهما أكثر منطقية قد يعتمد على طلبك.
تعتبر الإستراتيجية رقم 1 أكثر مثالية لأنها تقيس التعقيد الفعلي للآلة التي تحتوي على جميع القواعد. عندما يكون ذلك ممكنا، ينبغي استخدام هذه الاستراتيجية. الجانب السلبي هو، لنفترض أن لديك مستوى تحكم يسمح بإنشاء قاعدة واحدة في كل مرة، حتى عدد كبير جدًا. ثم بالنسبة لكل عملية من عمليات مستوى التحكم هذه، يجب عليك تحميل كافة القواعد الموجودة لإجراء التحقق من الصحة. قد يكون هذا مكلفًا للغاية. كما أنه عرضة لظروف السباق. الإستراتيجية رقم 2 هي حل وسط. ستكون العتبة التي تستخدمها الإستراتيجية رقم 2 أقل من الإستراتيجية رقم 1 نظرًا لأنها عتبة لكل قاعدة. لنفترض أنك تريد ألا يزيد تعقيد الآلة، مع إضافة جميع القواعد، عن 300. ثم باستخدام الاستراتيجية رقم 2، على سبيل المثال، يمكنك قصر كل آلة ذات قاعدة واحدة على تعقيد قدره 10، والسماح بـ 30 قاعدة تحتوي على أنماط أحرف البدل . في أسوأ الحالات على الإطلاق، حيث يكون التعقيد مضافًا تمامًا (وهو أمر غير مرجح)، قد يؤدي هذا إلى آلة يبلغ تعقيدها 300. الجانب السلبي هو أنه من غير المرجح أن يكون التعقيد مضافًا تمامًا، وبالتالي فإن عدد القواعد التي تحتوي على أحرف البدل سوف يتغير. من المحتمل أن تكون محدودة دون داع.
بالنسبة للاستراتيجية رقم 2، اعتمادًا على كيفية تخزين القواعد، قد يلزم إضافة سمة إضافية إلى القواعد للإشارة إلى القواعد غير المحددة (أي تحتوي على أنماط أحرف البدل) من أجل الحد من عدد القواعد التي تحتوي على أحرف البدل.
فيما يلي مقتطف من التعليمات البرمجية يوضح كيفية الحد من التعقيد لنمط معين، مثل الإستراتيجية رقم 2.
public class Validate { private void validate ( String pattern , MachineComplexityEvaluator machineComplexityEvaluator ) { // If we cannot compile, then return exception. List < Map < String , List < Patterns >>> compilationResult = Lists . newArrayList (); try { compilationResult . addAll ( JsonRuleCompiler . compile ( pattern )); } catch ( Exception e ) { InvalidPatternException internalException = EXCEPTION_FACTORY . invalidPatternException ( e . getLocalizedMessage ()); throw ExceptionMapper . mapToModeledException ( internalException ); } // Validate wildcard patterns. Look for wildcard patterns out of all patterns that have been used. Machine machine = new Machine (); int i = 0 ; for ( Map < String , List < Patterns >> rule : compilationResult ) { if ( containsWildcard ( rule )) { // Add rule to machine for complexity evaluation. machine . addPatternRule ( Integer . toString (++ i ), rule ); } } // Machine has all rules containing wildcard match types. See if the complexity is under the limit. int complexity = machine . evaluateComplexity ( machineComplexityEvaluator ); if ( complexity > MAX_MACHINE_COMPLEXITY ) { InvalidPatternException internalException = EXCEPTION_FACTORY . invalidPatternException ( "Rule is too complex" ); throw ExceptionMapper . mapToModeledException ( internalException ); } } private boolean containsWildcard ( Map < String , List < Patterns >> rule ) { for ( List < Patterns > fieldPatterns : rule . values ()) { for ( Patterns fieldPattern : fieldPatterns ) { if ( fieldPattern . type () == WILDCARD || fieldPattern . type () == ANYTHING_BUT_WILDCARD ) { return true ; } } } return false ; } }
يقوم الفصل الرئيسي الذي ستتفاعل معه بتطبيق مطابقة القواعد القائمة على آلة الحالة. الأساليب المثيرة للاهتمام هي:
addRule()
- يضيف قاعدة جديدة إلى الجهازdeleteRule()
- يحذف قاعدة من الجهازrulesForEvent()
/ rulesForJSONEvent()
- يبحث عن القواعد الموجودة في الجهاز التي تطابق حدثًا ما هناك نوعان من النكهات: Machine
و GenericMachine
. الآلة هي ببساطة GenericMachine
. تشير واجهة برمجة التطبيقات (API) إلى النوع العام باسم "الاسم"، والذي يعكس التاريخ: تم إنشاء إصدار السلسلة أولاً، وكان يُنظر إلى السلاسل التي تم تخزينها وإعادتها على أنها أسماء قواعد.
من أجل السلامة، يجب أن يكون النوع المستخدم لقواعد "التسمية" غير قابل للتغيير. إذا قمت بتغيير محتوى كائن أثناء استخدامه كاسم قاعدة، فقد يؤدي ذلك إلى تعطيل تشغيل المسطرة.
تقبل منشئات GenericMachine وMachine بشكل اختياري كائن GenericMachineConfiguration، الذي يعرض خيارات التكوين التالية.
الافتراضي: خطأ عادةً، يتم إعادة استخدام NameStates لتسلسل مفتاح ونمط محددين إذا تمت إضافة هذا النمط والتسلسل الرئيسي مسبقًا، أو إذا تمت إضافة نمط بالفعل لتسلسل المفتاح المحدد. وبالتالي، بشكل افتراضي، تكون إعادة استخدام NameState انتهازية. ولكن من خلال تعيين هذه العلامة على "صحيح"، سيتم فرض إعادة استخدام NameState لتسلسل رئيسي. هذا يعني أن النمط الأول الذي تتم إضافته لتسلسل مفتاح لاحق سيعيد استخدام NameState إذا تمت إضافة تسلسل المفتاح هذا من قبل. وهذا يعني أن كل تسلسل رئيسي له حالة اسم واحدة. يعمل هذا على تحسين استخدام الذاكرة بشكل كبير في بعض الحالات ولكنه يؤدي إلى تخزين المزيد من القواعد الفرعية في NameStates الفردية، والتي تتكرر المسطرة عليها أحيانًا، مما قد يتسبب في تراجع متواضع في أداء وقت التشغيل. يتم تعيين هذا افتراضيًا على "خطأ" للتوافق مع الإصدارات السابقة، ولكن من المحتمل أن تستفيد جميع التطبيقات، باستثناء التطبيقات الأكثر حساسية لزمن الاستجابة، من تعيين هذا على "صحيح".
وهنا مثال بسيط. يعتبر:
machine . addRule ( "0" , "{"key1": ["a", "b", "c"]}" ) ;
يقوم النمط "a" بإنشاء NameState، وبعد ذلك، حتى مع extraNameStateReuse=false، فإن النمط الثاني ("b") والنمط الثالث ("c") يعيدان استخدام نفس NameState. لكن ضع في اعتبارك ما يلي بدلاً من ذلك:
machine . addRule ( "0" , "{"key1": ["a"]}" ) ;
machine . addRule ( "1" , "{"key1": ["b"]}" ) ;
machine . addRule ( "2" , "{"key1": ["c"]}" ) ;
الآن، مع extraNameStateReuse=false، سينتهي بنا الأمر بثلاث حالات NameState، لأن النمط الأول الذي نواجهه لتسلسل فرعي رئيسي في كل إضافة قاعدة سينشئ حالة NameState جديدة. لذلك، تحصل كل من "a" و"b" و"c" على حالات الاسم الخاصة بها. ومع ذلك، مع extraNameStateReuse=true، سيُنشئ "a" حالة NameState جديدة، ثم سيعيد "b" و"c" استخدام NameState نفسه. يتم تحقيق ذلك من خلال تخزين أن لدينا بالفعل حالة اسم للتسلسل الرئيسي "key1".
لاحظ أنه لا يهم إذا كان كل addRule يستخدم اسم قاعدة مختلفًا أو نفس اسم القاعدة.
جميع أشكال هذه الطريقة لها نفس الوسيط الأول، وهي سلسلة توفر اسم القاعدة ويتم إرجاعها بواسطة rulesForEvent()
. توفر بقية الوسائط أزواج الاسم/القيمة. يمكن توفيرها بتنسيق JSON كما في الأمثلة أعلاه (عبر String أو Reader أو InputStream أو byte[]
) أو على شكل Map
، حيث المفاتيح هي أسماء الحقول و القيم هي قائمة التطابقات المحتملة؛ باستخدام المثال أعلاه، سيكون هناك مفتاح اسمه detail.state
وقيمته هي القائمة التي تحتوي على "initializing"
و "running"
.
ملاحظة: تتم مزامنة هذه الطريقة (وكذلك deleteRule()
) لذا قد يقوم مؤشر ترابط واحد فقط بتحديث الجهاز في أي وقت.
يمكنك استدعاء addRule()
عدة مرات بنفس الاسم ولكن مع عدة أنماط مختلفة من الأسماء/القيم، وبالتالي تحقيق علاقة "أو"؛ سوف تُرجع rulesForEvent()
هذا الاسم في حالة تطابق أي من الأنماط.
على سبيل المثال، لنفترض أنك قمت باستدعاء addRule()
باسم القاعدة كـ "R1" وأضفت النمط التالي:
{
"detail" : {
"c-count" : [ { "numeric" : [ ">" , 0 , "<=" , 5 ] } ]
}
}
ثم تسميه مرة أخرى بنفس الاسم ولكن بنمط مختلف:
{
"detail" : {
"x-limit" : [ { "numeric" : [ "=" , 3.018e2 ] } ]
}
}
بعد ذلك، ستُرجع rulesForEvent()
"R1" إما لقيمة c-count
البالغة 2 أو قيمة x-limit
البالغة 301.8.
هذه صورة طبق الأصل لـ addRule()
; في كل حالة، تكون الوسيطة الأولى هي اسم القاعدة، ويتم تقديمها كسلسلة. توفر الوسيطات اللاحقة الأسماء والقيم، ويمكن تقديمها بأي من الطرق نفسها المستخدمة في addRule()
.
ملاحظة: تتم مزامنة هذه الطريقة (وأيضًا addRule()
) لذا قد يقوم مؤشر ترابط واحد فقط بتحديث الجهاز في أي وقت.
يمكن أن يكون تشغيل واجهة برمجة التطبيقات هذه دقيقًا. يقوم الجهاز بتجميع تعيين أنماط الاسم/القيمة لأسماء القواعد في آلي محدود، لكنه لا يتذكر الأنماط التي تم تعيينها لاسم قاعدة معين. وبالتالي، ليس هناك أي شرط بأن يتطابق النمط الموجود في deleteRule()
تمامًا مع النمط الموجود في addRule()
المطابق. سوف يبحث المسطرة عن المطابقات لأنماط الاسم/القيمة ويرى ما إذا كانت تتطابق مع قاعدة بالاسم المقدم، وإذا كان الأمر كذلك، فسيقوم بإزالتها. ضع في اعتبارك أنه أثناء إجراء استدعاءات deleteRule()
التي لا تتطابق تمامًا مع استدعاءات addRule()
المقابلة لن تفشل ولن تترك الجهاز في حالة غير متناسقة، بل قد تتسبب في تراكم "البيانات المهملة" في الجهاز.
والنتيجة المحددة هي أنه إذا قمت باستدعاء addRule()
عدة مرات بنفس الاسم ولكن بأنماط مختلفة، كما هو موضح أعلاه في قسم القواعد وأسماء القواعد ، فسيتعين عليك استدعاء deleteRule()
بنفس عدد المرات، بنفس الأنماط المرتبطة، لإزالة كافة الإشارات إلى اسم القاعدة من الجهاز.
تقوم هذه الطريقة بإرجاع List
for Machine (و List
لـ GenericMachine) والتي تحتوي على أسماء القواعد التي تطابق الحدث المقدم. قد يتم توفير الحدث لأي من الطريقتين String
واحدة تمثل نموذج JSON الخاص به.
يمكن أيضًا توفير الحدث إلى rulesForEvent()
كمجموعة من السلاسل التي تتبادل أسماء الحقول وقيمها، ويجب فرزها بشكل معجمي حسب اسم الحقل. قد يكون هذا List
أو String[]
.
يعد توفير الحدث بتنسيق JSON هو الأسلوب الموصى به وله العديد من المزايا. أولاً، يعد ملء قائمة السلسلة أو المصفوفة بكميات الاسم/القيمة البديلة، بترتيب تم فرزه حسب الاسم، أمرًا صعبًا، ولا يساعد المسطرة، فقط يفشل في العمل بشكل صحيح إذا تم تنظيم القائمة بشكل غير صحيح. ومما يزيد من الصعوبة أن تمثيل قيم الحقول، المقدمة كسلاسل، يجب أن يتبع قواعد بناء جملة JSON - انظر أدناه ضمن مطابقة نص JSON .
وأخيرًا، فإن إصدار القائمة/المصفوفة للحدث يجعل من المستحيل على المسطرة التعرف على بنيات المصفوفة وتوفير مطابقة متسقة للمصفوفة، كما هو موضح أدناه في هذا المستند. تم إهمال واجهة API rulesForEvent(String eventJSON)
لصالح rulesForJSONEvent()
على وجه التحديد لأنها لا تدعم المطابقة المتسقة للصفيف.
تتمتع rulesForJSONEvent()
أيضًا بميزة أن الكود الذي يحول نموذج JSON للحدث إلى قائمة مرتبة قد تم تحديده وتحسينه على نطاق واسع.
لا يعتمد أداء rulesForEvent()
و rulesForJSONEvent()
على عدد القواعد المضافة باستخدام addRule()
. rulesForJSONEvent()
أسرع بشكل عام بسبب المعالجة المحسنة للأحداث. إذا كنت تقوم بمعالجة الأحداث الخاصة بك واستدعاء rulesForEvent()
بقائمة من الأسماء والقيم تم فرزها مسبقًا، فسيكون ذلك أسرع؛ ولكن قد لا تتمكن من إعداد قائمة الحقول بالسرعة التي تفعلها rulesForJSONEvent()
.
هذه الطريقة تقريبية لعدد الكائنات الموجودة داخل الجهاز. تختلف قيمتها فقط عند إضافة القاعدة أو إزالتها. يعد هذا مفيدًا لتحديد الأجهزة الكبيرة التي قد تتطلب قدرًا كبيرًا من الذاكرة. وبما أن هذه الطريقة تعتمد على عدد الكائنات الداخلية، فقد يتغير هذا التعداد عند تغيير العناصر الداخلية لمكتبة المسطرة. تقوم الطريقة بتنفيذ كافة العمليات الحسابية الخاصة بها في وقت التشغيل لتجنب استهلاك الذاكرة وجعل تأثير أجهزة القواعد الكبيرة أسوأ. إن حسابه ليس آمنًا عن قصد لتجنب حظر تقييمات القواعد وتغييرات الجهاز. ويعني ذلك أنه في حالة إضافة أو إزالة عملية متوازية من الجهاز، فقد تحصل على نتائج مختلفة مقارنة بوقت اكتمال هذه العمليات المتوازية. أيضًا، نظرًا لأن المكتبة تجري تحسينات على أجهزتها الداخلية لبعض الأنماط (راجع ShortcutTransition.java
لمزيد من التفاصيل)، فقد تحصل أيضًا على نتائج مختلفة اعتمادًا على الترتيب الذي تمت به إضافة القواعد أو إزالتها.
إذا كنت تفكر في الأحداث الخاصة بك كأزواج اسم/قيمة بدلاً من مستندات نمط JSON المتداخلة، فقد تكون فئة Patterns
(والنطاق Range
الخاص بها) مفيدة في إنشاء القواعد. الطرق الثابتة التالية مفيدة.
public static ValuePatterns exactMatch ( final String value );
public static ValuePatterns prefixMatch ( final String prefix );
public static ValuePatterns prefixEqualsIgnoreCaseMatch ( final String prefix );
public static ValuePatterns suffixMatch ( final String suffix );
public static ValuePatterns suffixEqualsIgnoreCaseMatch ( final String suffix );
public static ValuePatterns equalsIgnoreCaseMatch ( final String value );
public static ValuePatterns wildcardMatch ( final String value );
public static AnythingBut anythingButMatch ( final String anythingBut );
public static AnythingBut anythingButMatch ( final Set < String > anythingButs );
public static AnythingBut anythingButMatch ( final double anythingBut );
public static AnythingBut anythingButNumberMatch ( final Set < Double > anythingButs );
public static AnythingButValuesSet anythingButPrefix ( final String prefix );
public static AnythingButValuesSet anythingButPrefix ( final Set < String > anythingButs );
public static AnythingButValuesSet anythingButSuffix ( final String suffix );
public static AnythingButValuesSet anythingButSuffix ( final Set < String > anythingButs );
public static AnythingButValuesSet anythingButIgnoreCaseMatch ( final String anythingBut );
public static AnythingButValuesSet anythingButIgnoreCaseMatch ( final Set < String > anythingButs );
public static AnythingButValuesSet anythingButWildcard ( final String value );
public static AnythingButValuesSet anythingButWildcard ( final Set < String > anythingButs );
public static ValuePatterns numericEquals ( final double val );
public static Range lessThan ( final double val );
public static Range lessThanOrEqualTo ( final double val );
public static Range greaterThan ( final double val );
public static Range greaterThanOrEqualTo ( final double val );
public static Range between ( final double bottom , final boolean openBottom , final double top , final boolean openTop );
بمجرد إنشاء مطابقات Patterns
المناسبة باستخدام هذه الطرق، يمكنك استخدام الطرق التالية للإضافة إلى جهازك أو الحذف منه:
public void addPatternRule ( final String name , final Map < String , List < Patterns >> namevals );
public void deletePatternRule ( final String name , final Map < String , List < Patterns >> namevals );
ملاحظة: تنطبق التحذيرات المذكورة في deleteRule()
على deletePatternRule()
أيضًا.
يجب توفير قيم الحقول في القواعد في تمثيلات JSON الخاصة بها. وهذا يعني أن قيم السلسلة يجب أن تكون محاطة بعلامات اقتباس. يُسمح بالقيم غير المقتبسة، مثل الأرقام ( -3.0e5
) وبعض القيم الحرفية الخاصة بـ JSON ( true
و false
و null
).
يمكن تجاهل ذلك تمامًا إذا تم توفير القواعد إلى addRule()
() في نموذج JSON، أو إذا كنت تعمل باستخدام الأنماط بدلاً من السلاسل الحرفية. لكن إذا كنت تقدم قواعد كأزواج اسم/قيمة، وتريد تحديد أن الحقل "xyz" يطابق السلسلة "true"، فيجب التعبير عن ذلك كـ "xyz", ""true""
. من ناحية أخرى، "xyz", "true"
سوف يتطابق فقط مع JSON الحرفي true
.
تدعم المسطرة مطابقة القواعد للأحداث التي تحتوي على صفائف، ولكن فقط عندما يتم توفير الحدث في نموذج JSON - عندما تكون قائمة بالحقول التي تم فرزها مسبقًا، يتم فقدان بنية المصفوفة في الحدث. يعتمد السلوك أيضًا على ما إذا كنت تستخدم rulesForEvent()
أو rulesForJSONEvent
.
النظر في الحدث التالي.
{
"employees" : [
{ "firstName" : "John" , "lastName" : "Doe" } ,
{ "firstName" : "Anna" , "lastName" : "Smith" } ,
{ "firstName" : "Peter" , "lastName" : "Jones" }
]
}
ثم سوف تتطابق هذه القاعدة:
{ "employees" : { "firstName" : [ "Anna" ] } }
وهذا يعني أن بنية الصفيف "يتم سحقها" من نمط القاعدة، ويتم التعامل مع أي كائنات مضمنة كما لو كانت قيمة الحقل الأصلي. يعمل هذا أيضًا مع المصفوفات متعددة المستويات:
{
"employees" : [
[
{ "firstName" : "John" , "lastName" : "Doe" } ,
{ "firstName" : "Anna" , "lastName" : "Smith" }
] ,
[
{ "firstName" : "Peter" , "lastName" : "Jones" }
]
]
}
في الإصدارات السابقة من المسطرة، كانت طريقة المطابقة الوحيدة المستندة إلى الآلة هي rulesForEvent()
والتي ستطابق للأسف أيضًا القاعدة التالية:
{ "employees" : { "firstName" : [ "Anna" ] , "lastName" : [ "Jones" ] } }
كحل للمشكلة، قدم المسطرة rulesForJSONEvent()
والتي، كما يوحي الاسم، تتطابق فقط مع الأحداث المقدمة في نموذج JSON. لن تتطابق rulesForJsonEvent()
مع قاعدة "Anna"/"Jones" أعلاه.
رسميًا: سترفض rulesForJSONEvent()
التعرف على أي تطابق يكون فيه أي حقلين ضمن كائنات JSON الموجودة في عناصر مختلفة من نفس المصفوفة. من الناحية العملية، هذا يعني أنه يفعل ما تتوقعه.
هناك فئة داعمة com.amazon.fsm.ruler.RuleCompiler
. يحتوي على طريقة تسمى check()
والتي تقبل تعريف قاعدة JSON وترجع قيمة سلسلة، إذا كانت فارغة، فهذا يعني أن القاعدة كانت صالحة من الناحية النحوية. إذا كانت القيمة المرجعة غير خالية، فإنها تحتوي على رسالة خطأ يمكن قراءتها بواسطة الإنسان تصف المشكلة.
من أجل الراحة، فهو يحتوي أيضًا على طريقة تسمى compile()
والتي تعمل تمامًا مثل check()
ولكنها تشير إلى خطأ عن طريق طرح IOException، وعند النجاح، تُرجع Map
بالشكل الذي يشير إليه addRule()
الخاص بالجهاز addRule()
تتوقع الطريقة. نظرًا لأن فئة الآلة تستخدم هذا داخليًا، فقد تكون هذه الطريقة موفرة للوقت.
عندما يجمع المسطرة المفاتيح، فإنه يستخدم النقطة ( .
) كحرف الربط. وهذا يعني أنه سيتم تجميع القاعدتين التاليتين لنفس التمثيل الداخلي
## has no dots in keys
{ "detail" : { "state" : { "status" : [ "running" ] } } }
## has dots in keys
{ "detail" : { "state.status" : [ "running" ] } }
ويعني أيضًا أن هذه القواعد ستتطابق مع الحدثين التاليين:
## has no dots in keys
{ "detail" : { "state" : { "status" : "running" } } }
## has dots in keys
{ "detail" : { "state.status" : "running" } }
قد يتغير هذا السلوك في الإصدار المستقبلي (لتجنب أي التباسات) ولا ينبغي الاعتماد عليه.
نحن نقيس أداء المسطرة من خلال تجميع قواعد متعددة في جهاز ومطابقة الأحداث المقدمة كسلاسل JSON.
معيار يعالج 213,068 حدث JSON بمتوسط حجم حوالي 900 بايت مقابل 5 لكل تطابق تام، ومطابقة بادئة، ومطابقة لاحقة، ومطابقة حالة الأحرف يساوي تجاهل، ومطابقة أحرف البدل، ومطابقة رقمية، وأي شيء غير المطابقة قواعد وحساب المطابقات، وتنتج ما يلي على جهاز MacBook 2019:
تتم معالجة الأحداث بسرعة تزيد عن 220 ألف/الثانية باستثناء:
فيما يلي بعض الاقتراحات حول قواعد المعالجة والأحداث:
من حيث اعتبارات الأداء، تعتبر المسطرة حساسة للعناصر أدناه، لذلك، عندما تقوم بتصميم مخطط الحدث والقاعدة، إليك بعض الاقتراحات:
انظر المساهمة لمزيد من المعلومات.
تم ترخيص هذا المشروع بموجب ترخيص Apache-2.0. راجع الترخيص لمزيد من المعلومات.