Event Ruler(為簡潔起見,在文件的其餘部分中稱為 Ruler)是一個 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"
}
}
您也可以將其視為一組名稱/值對。為簡潔起見,我們僅提供一個範例。 Ruler 具有用於以 JSON 形式和名稱/值對的形式提供事件的 API:
+--------------+------------------------------------------+
| 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" } } ]
}
前綴 equals-ignore-case 匹配僅適用於字串值欄位。
{
"source" : [ { "suffix" : "ec2" } ]
}
後綴匹配僅適用於字串值欄位。
{
"source" : [ { "suffix" : { "equals-ignore-case" : "EC2" } } ]
}
後綴 equals-ignore-case 匹配僅適用於字串值欄位。
{
"source" : [ { "equals-ignore-case" : "EC2" } ]
}
等於忽略大小寫匹配僅適用於字串值欄位。
{
"source" : [ { "wildcard" : "Simple*Service" } ]
}
通配符匹配僅適用於字串值欄位。單一值可以包含零到多個通配符,但不允許連續的通配符。為了專門匹配星號字符,可以使用反斜線轉義通配符。兩個連續的反斜線(即用反斜線轉義的反斜線)代表實際的反斜線字元。不允許使用反斜線轉義星號或反斜線以外的任何字元。
Anything-but 符合顧名思義:符合規則中提供的內容之外的任何內容。
Anything-but 適用於單一字串和數值或列表,其中必須完全包含字串或完全數字。它也可以應用於字串或字串列表的前綴、後綴或等於忽略大小寫匹配。
單一任何內容(字串,然後是數字):
{
"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 數字的值。數位匹配支援與 Java 的double
原語相同的精確度和範圍,後者實現 IEEE 754 binary64
標準。
{
"detail" : {
"source-ip" : [ { "cidr" : "10.0.0.0/24" } ]
}
}
這也適用於 IPv6 位址。
存在匹配適用於 JSON 事件中是否存在欄位。
下面的規則將符合任何具有detail.c-count 欄位的事件。
{
"detail" : {
"c-count" : [ { "exists" : true } ]
}
}
下面的規則將符合任何沒有detail.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" } ]
}
}
如上面的範例所示,如果規則中命名的所有欄位都匹配,則 Ruler 認為該規則匹配;如果提供的任何欄位值匹配,則認為該欄位匹配,也就是說 Ruler 應用了「與」邏輯預設情況下,所有欄位都不需要「And」原語。
有兩種方法可以達到「或」效果:
「$or」原語允許客戶直接描述規則中欄位之間的「或」關係。
只有當規則滿足以下所有條件時,標尺才識別「或」關係:
/src/main/software/amazon/event/ruler/Constants.java#L38
中的RESERVED_FIELD_NAMES_IN_OR_RELATIONSHIP 例如,以下規則將不會被解析為“或”關係,因為“數字”和“前綴”是標尺保留關鍵字。 {
"$or": [ {"numeric" : 123}, {"prefix": "abc"} ]
}
否則,Ruler 僅將「$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 盡力保持向後相容性。只有在滿足上述 3 個條件時,統治者才會改變行為,因為它假設您的規則確實需要 OR 並且直到今天才配置錯誤。例如,下面的規則將繼續作為正常規則工作,並將「$or」視為規則和事件中的正常欄位名稱:
{
"source" : [ "aws.cloudwatch" ] ,
"$or" : {
"metricType" : [ "MetricType" ] ,
"namespace" : [ "AWS/EC2" , "AWS/ES" ]
}
}
有關「$or」被 Ruler 解析為普通欄位名稱的更多範例,請參閱/src/test/data/normalRulesWithOrWording.json
。
作為「Or」關係原語的關鍵字「$or」不應被設計為事件和規則中的普通欄位。 Ruler 支援舊規則,其中「$or」被解析為普通欄位名稱,以保持向後相容性,並為團隊提供時間將舊的「$or」用法從事件和規則中遷移為普通欄位名稱。 Ruler 故意不支援混合使用「$or」作為「Or」原語和「$or」作為普通欄位名稱,以避免「$or」上出現超級尷尬的歧義。
有兩種使用標尺的方法。您可以將多個規則編譯為“機器”,然後使用其rulesForEvent()
方法或rulesForJSONEvent()
方法來檢查哪些規則與任何事件相符。下面討論這兩種方法之間的差異。本討論將一般使用rulesForEvent()
除非差異很重要。
或者,您可以使用單一靜態布林方法來確定單一事件是否與特定規則相符。
有一個靜態布林方法Ruler.matchesRule(event, rule)
- 兩個參數都以 JSON 字串形式提供。
注意:還有另一種已棄用的方法,稱為Ruler.matches(event, rule)
,不應使用該方法,因為其結果與rulesForJSONEvent()
和rulesForEvent()
不一致。有關詳細信息,請參閱有關Ruler.matches(event, rule)
的文檔。
匹配時間不依賴規則的數量。如果您有多個可能的規則想要從中進行選擇,特別是如果您有辦法儲存已編譯的 Machine,那麼這是最佳選擇。
匹配時間受到通配符和非通配符規則引起的不確定性程度的影響。隨著越來越多的通配符規則前綴與理論上的最壞情況事件匹配,效能會下降。為了避免這種情況,與相同事件欄位相關的通配符規則應避免導致第一個通配符的公共前綴。如果需要公共前綴,則使用最少數量的通配符,並限制通配符後面出現的重複字元序列。 MachineComplexityEvaluator 可用於評估機器並確定不確定性或「複雜性」的程度(即有多少通配符規則前綴與理論上的最壞情況事件相符)。以下是一些數據點,顯示隨著複雜性分數的增加,效能通常會下降。
限制機器複雜性以保護您的應用程式非常重要。至少有兩種不同的策略來限制機器的複雜性。哪一種更有意義可能取決於您的應用程式。
策略#1 更理想,因為它測量包含所有規則的機器的實際複雜性。如果可能,應使用此策略。缺點是,假設您有一個控制平面,允許一次建立一個規則,最多可以建立一個非常大的數量。然後,對於每個控制平面操作,您必須載入所有現有規則來執行驗證。這可能非常昂貴。它也容易出現競爭條件。策略#2 是一種妥協。策略 #2 使用的閾值將低於策略 #1,因為它是每個規則的閾值。假設您希望新增所有規則後機器的複雜度不超過 300。在複雜性完全相加(不太可能)的絕對最壞情況下,這將導致機器的複雜性為 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
。 Machine 就是GenericMachine
。 API 將泛型類型稱為“名稱”,這反映了歷史:首先建立了 String 版本,它儲存和傳回的字串被視為規則名稱。
為了安全起見,用於「命名」規則的類型應該是不可變的。如果在將物件用作規則名稱時變更物件的內容,則可能會破壞標尺的操作。
GenericMachine 和 Machine 建構函式可以選擇接受 GenericMachineConfiguration 對象,該物件公開以下配置選項。
預設值: false 通常,如果先前已新增給定鍵子序列和模式,或已為給定鍵子序列新增了模式,則 NameState 會重新用於給定鍵子序列和模式。因此,預設情況下,NameState 重複使用是機會主義的。但將此標誌設為 true,將強制對關鍵子序列重複使用 NameState。這意味著,如果先前已新增該鍵子序列,則為該鍵子序列新增的第一個模式將重新使用 NameState。這意味著每個鍵子序列都有一個 NameState。在某些情況下,這會以指數方式提高記憶體利用率,但確實會導致更多子規則儲存在各個 NameState 中,Ruler 有時會對其進行迭代,這可能會導致運行時效能適度下降。為了向後相容,此值預設為 false,但很可能,除了對延遲最敏感的應用程式之外,所有應用程式都將從將其設為 true 中受益。
這是一個簡單的例子。考慮:
machine . addRule ( "0" , "{"key1": ["a", "b", "c"]}" ) ;
模式「a」建立一個NameState,然後,即使additionalNameStateReuse=false,第二個模式(「b」)和第三個模式(「c」)也會重複使用相同的NameState。但請考慮以下幾點:
machine . addRule ( "0" , "{"key1": ["a"]}" ) ;
machine . addRule ( "1" , "{"key1": ["b"]}" ) ;
machine . addRule ( "2" , "{"key1": ["c"]}" ) ;
現在,如果additionalNameStateReuse=false,我們最終會得到三個NameState,因為每個規則新增中關鍵子序列遇到的第一個模式將建立一個新的NameState。因此,「a」、「b」和「c」都有自己的 NameState。然而,當additionalNameStateReuse=true時,「a」會建立一個新的NameState,然後「b」和「c」將會重複使用這個相同的NameState。這是透過儲存我們已經擁有鍵子序列「key1」的 NameState 來完成的。
請注意,每個 addRule 使用不同的規則名稱或相同的規則名稱並不重要。
此方法的所有形式都具有相同的第一個參數,即提供規則名稱並由rulesForEvent()
傳回的字串。其餘參數提供名稱/值對。它們可以像上面的範例一樣以 JSON 形式提供(透過 String、Reader、InputStream 或byte[]
),或以Map
提供,其中鍵是欄位名稱和值是可能匹配的清單;使用上面的範例,將有一個名為detail.state
的鍵,其值將是包含"initializing"
和"running"
的清單。
注意:此方法(以及deleteRule()
)是同步的,因此在任何時間點都可能只有一個執行緒更新機器。
您可以使用相同的名稱但多個不同的名稱/值模式多次呼叫addRule()
,從而實現「或」關係;如果任何模式匹配, rulesForEvent()
將返回該名稱。
例如,假設您呼叫規則名稱為「R1」的addRule()
並新增下列模式:
{
"detail" : {
"c-count" : [ { "numeric" : [ ">" , 0 , "<=" , 5 ] } ]
}
}
然後使用相同的名稱但不同的模式再次呼叫它:
{
"detail" : {
"x-limit" : [ { "numeric" : [ "=" , 3.018e2 ] } ]
}
}
此後,對於c-count
數值 2或x-limit
值 301.8, rulesForEvent()
將傳回「R1」。
這是addRule()
的鏡像;在每種情況下,第一個參數都是規則名稱,以字串形式給出。後續參數提供名稱和值,並且可以透過與addRule()
相同的任何方式給出。
注意:此方法(以及addRule()
)是同步的,因此在任何時間點都可能只有一個執行緒更新機器。
該 API 的操作可能很微妙。機器將名稱/值模式到規則名稱的對應編譯成有限自動機,但不記得哪些模式對應到給定的規則名稱。因此,不要求deleteRule()
中的模式與對應的addRule()
中的模式完全匹配。 Ruler 將尋找名稱/值模式的匹配項,並查看它們是否與具有所提供名稱的規則匹配,如果是,則刪除它們。請記住,雖然執行與相應的 addRule( deleteRule()
addRule()
呼叫不會失敗,並且不會使機器處於不一致的狀態,但它們可能會導致機器中堆積「垃圾」。
一個特定的結果是,如果您使用相同的名稱但不同的模式多次呼叫addRule()
,如上面的規則和規則名稱部分所示,則必須使用相同的名稱呼叫deleteRule()
相同的次數。 ,以從電腦中刪除對該規則名稱的所有引用。
此方法傳回 Machine 的List
(對於 GenericMachine 傳回List
),其中包含與提供的事件相符的規則的名稱。事件可以作為表示其 JSON 形式的單一String
提供給任一方法。
該事件也可以作為交替欄位名稱和值的字串集合提供給rulesForEvent()
,並且必須按欄位名稱按詞法排序。這可能是List
或String[]
。
以 JSON 形式提供事件是推薦的方法,並且具有多個優點。首先,按名稱排序的順序用交替的名稱/值數量填充字串列表或數組是很棘手的,並且標尺沒有幫助,如果列表結構不正確,則無法正常工作。更困難的是,以字串形式提供的欄位值的表示必須遵循 JSON 語法規則 - 請參閱下面的JSON 文字匹配。
最後,事件的列表/數組版本使得 Ruler 無法識別數組結構並提供數組一致的匹配,如本文檔下面所述。不建議使用rulesForEvent(String eventJSON)
API,而是使用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
)。
如果以 JSON 形式向addRule()
() 提供規則,或者如果您使用模式而不是文字字串,則可以完全忽略這一點。但是,如果您以名稱/值對的形式提供規則,並且想要指定欄位 "xyz" 與字串 "true" 匹配,則必須將其表示為"xyz", ""true""
。另一方面, "xyz", "true"
將只符合 JSON 文字true
。
Ruler 支援對包含數組的事件進行規則匹配,但僅當事件以 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" }
]
]
}
在早期版本的 Ruler 中,唯一基於機器的匹配方法是rulesForEvent()
,不幸的是它也將匹配以下規則:
{ "employees" : { "firstName" : [ "Anna" ] , "lastName" : [ "Jones" ] } }
作為修復,Ruler 引入了rulesForJSONEvent()
,顧名思義,它僅匹配以 JSON 形式提供的事件。 rulesForJsonEvent()
不會符合上面的「Anna」/「Jones」規則。
正式來說: rulesForJSONEvent()
將拒絕識別任何兩個字段位於同一數組的不同元素中的 JSON 物件內的任何匹配。實際上,這意味著它符合您的預期。
有一個支援類com.amazon.fsm.ruler.RuleCompiler
。它包含一個名為check()
的方法,該方法接受 JSON 規則定義並傳回一個 String 值,如果為 null,則表示該規則在語法上有效。如果傳回值非 Null,則它包含描述問題的人類可讀錯誤訊息。
為了方便起見,它還包含一個名為compile()
方法,它的工作方式與check()
類似,但透過拋出IOException來發出錯誤訊號,並在成功時以Machine的addRule()
的形式傳回Map
addRule()
方法期望。由於 Machine 類別在內部使用此方法,因此此方法可能會節省時間。
當 Ruler 編譯鍵時,它使用點 ( .
) 作為連接字元。這意味著它將把以下兩個規則編譯為相同的內部表示
## 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 字串形式提供的事件來衡量 Ruler 的效能。
一個基準測試,處理 213,068 個 JSON 事件,平均大小約為 900 字節,每個事件有 5 個完全匹配、前綴匹配、後綴匹配、等於忽略大小寫匹配、通配符匹配、數字匹配和非匹配的內容規則並計算匹配數,在2019 年MacBook 上產生以下結果:
事件處理速度超過 220K/秒,但以下情況除外:
以下是一些關於處理規則和事件的建議:
從效能考慮,Ruler 對以下幾項比較敏感,因此,當您設計事件和規則的架構時,這裡有一些建議:
請參閱貢獻以獲取更多資訊。
該專案根據 Apache-2.0 許可證獲得許可。請參閱許可證以了解更多資訊。