NIFI JoltTransFormJson JOLT SPEC的寫法

# 一、jolt插件介紹

## 1、jolt插件使用簡介:
jolt插件的主要作用是將一種json格式轉化爲另一種json格式,它通過使用配置文件定義轉換規則的方法,使得json轉換可配置,只要輸入的json格式是固定的就可以使用jolt進行轉換。
[[ http://jolt-demo.appspot.com/#andrewkcarter2 | jolt插件鏈接 ]]

## 2、jolt插件主要轉換方法
插件提供了5種轉換方法:
  - 1、shift:主要作用是拷貝,將輸入json的某個結構拷貝到目標json。
  - 2、default:主要作用是設置默認值,如果輸入json某個value不存在,則使用默認值補齊。
  - 3、remove:主要作用是刪除,可以刪除輸入json結構的某個結構。
  - 4、sort:對key值進行排序。
  - 5、cardinality:jsonobject和jsonarray之間的切換。
目前主要用Shiftr這個類,java代碼如下:
```
Object input = JsonUtils.classpathToObject("/jolt/Shiftr/sample01/input.json");  // 讀取input.json,如果input已經是一個java對象,則可以忽略這步
Object spec = JsonUtils.classpathToObject("/jolt/Shiftr/sample01/spec.json");   // 使用Jolt自帶的JsonUtils讀取配置的轉換規則spec.json作爲一個object

Shiftr shiftr=new Shiftr(spec);  // 創建shiftr對象,傳入轉化規則
Object output = shiftr.transform(input);   // 轉換input,得到output
```
(NOTE)注:operation取值有shift,default,remove,cardinality,sort,每一種轉換的規則作爲spec的value。

# 二、基本通配符說明

##  “*”通配符
“*”通配符(僅可以匹配input的key,不能匹配value),使用 “*”通配符的時候,需要保證輸入json具有相同的層級結構,它可以匹配某一個層級結構中的所有key,也可以匹配一個key的部分字符。

##  “&”通配符
“&”通配符有兩個參數&(0,1),第一個參數0表示從input的什麼位置去找value,第二個參數1表示將找到的value放在匹配到的哪個位置。參數可以省略,&=&0=&(0)=&(0,0)。

## “$”通配符
$通配符和&通配符具有相同的語法結構,都有兩個參數,$通配符通常用法是將當前key值作爲output的value使用。

## “#”通配符
“#”通配符最有用的一點是,當input取不同值的時候,可以對output進行不同的操作,主要是賦值操作。

##  “|”通配符
“|”表示“或”的邏輯,很容易理解,它只會匹配寫出的字符。

## “@”通配符
“@”通配符也有兩個參數@(0,1),"@"和"$"用法類似,不過"@"取得是指定位置的value,而“$”取的是指定位置的key。

# 三、JOLT SPEC基本寫法總結
(NOTE)注:我理解JOLT SPEC寫法需要抓住幾個關鍵點:匹配;替換,輸入; JSON節點的引用;取值(鍵,值)。

## 1、替換JSON中的關鍵字
(NOTE)注:這個例子要理解匹配與替換

Json Input:
```
{
  "rating": {
    "primary": {
      "value": 3
    },
    "quality": {
      "value": 3
    }
  }
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "rating": {
        "primary": {
          "value": "Rating"
        }
      }
    }
  }
]
```

Output:
```
{
  "Rating" : 3
}
```

//說明//
> 1:“規範”節點中內容就是轉換JSON的核心方法。
> 2:匹配是按照輸入JSON的樹結構,父子節點的層次,關鍵的值進行的比如例子中先匹配了  "rating",然後是 "primary"...
> 3:匹配就是爲了替換,首先是節點的替換,比如匹配到了 "rating",而JOLT Spec“rating”後的:{}就替換掉了了這個節點。
> 4:然後是鍵值的替換,比如 "value":"Rating"所以
>      "value":3 - >"rating":3
>      而"rating":3替換了主要節點,替換了評級節點。
> 5:沒有匹配到的就被忽略掉。
> 6:匹配可以使用 “*”,全部匹配。

# 2、&節點位置輸入
Json Input:
```
{
  "rating": {
    "primary": {
      "value": "3",
      "max": 5
    },
    "quality": {
      "value": 3,
      "max": 5
    },
    "sharpness": {
      "value": 7,
      "max": 10
    }
  }
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "rating": {
        "primary": {
          "value": "Rating",
          "max": "RatingRange"
        },
        "*": {
          "max": "SecondaryRatings.&1.Range",
          "value": "SecondaryRatings.&1.Value",
          "$": "SecondaryRatings.&1.Id"
        }
      }
    }
  }
]
```

Output:
```
{
  "Rating" : "3",
  "RatingRange" : 5,
  "SecondaryRatings" : {
    "quality" : {
      "Id" : "quality",
      "Range" : 5,
      "Value" : 3
    },
    "sharpness" : {
      "Id" : "sharpness",
      "Range" : 10,
      "Value" : 7
    }
  }
}
```
//說明//
(NOTE)注:&1當前所在節點的父節點(即*)匹配到的密鑰值。

> 1: “*” 匹配等級下,除主(已匹配轉換)外其餘節點。
> 2:“value”:“SecondaryRatings.&1.Value”,到此,我們大概已經瞭解,SecondaryRatings.&1.Value是輸出json的節點結構,[]表示了層級關係,&1樹結構中level0,它的level1是“*”,&1即“*”匹配到的節點鍵。
> 3:$的作用也是取關鍵值,當前 “*” 匹配到的節點的關鍵值,不同與匹配的是, “$” 等不是匹配含義時,作用爲輸入。

繼續看例子:
Json Input:
```
{
  "rating": {
    "primary": {
      "value": 3,
      "max": 5
    },
    "quality": {
      "value": 3,
      "max": 7
    }
  }
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "rating": {
        "*": {
          "$(1)": "ratingNames[]"
        }
      }
    }
  }
]
```

Output:
```
{
  "ratingNames" : [ "rating", "rating" ]
}
```

//說明//
> $等價於$(0),$(1)即當前節點的父節點的密鑰值, []的作用表示ratingNames是一個數組, “*” 匹配到了兩個節點,這兩個節點輸入$(1)到ratingNames數組。

# 3、@#通配符
Json Input:
```
{
  "rating": {
    "primary": 5,
    "quality": 4,
    "design": 5
  }
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "rating": {
        "*": {
          "$": "Ratings[#2].Name",
          "@": "Ratings[#2].Value"
        }
      }
    }
  }
]
```

Output:
```
{
  "Ratings" : [ {
    "Name" : "primary",
    "Value" : 5
  }, {
    "Name" : "quality",
    "Value" : 4
  }, {
    "Name" : "design",
    "Value" : 5
  } ]
}
```

//說明//
> 1:@是取當前節點值。
> 2:$是取當前節點的關鍵值。
> 3:#2 :(畫節點樹去理解,弄清當前#在那個節點,再跳)跳到評分,訪問評級節點,統計評分有幾個子節點被匹配到了,統計數爲數組大小。

若果將#2換成#1呢(可以自己試着解析),也可以再多包裹幾層試試:
Json Input:
```
{
  "rating": {
    "primary": 5,
    "quality": 4,
    "design": 5
  }
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "rating": {
        "*": {
          "$": "Ratings[#1].Name",
          "@": "Ratings[#1].Value"
        }
      }
    }
  }
]
```

Output:
```
{
  "Ratings" : [ {
    "Name" : [ "primary", "quality", "design" ],
    "Value" : [ 5, 4, 5 ]
  } ]
}
```

# 4、@(,)
Json Input:
```
{
  "data": {
    "1234": {
      "clientId": "12",
      "hidden": true
    },
    "1235": {
      "clientId": "35",
      "hidden": false
    }
  }
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "data": {
        "*": {
          "hidden": {
            "true": {
              "#disabled": "clients.@(3,clientId)"
            },
            "false": {
              "#enabled": "clients.@(3,clientId)"
            }
          }
        }
      }
    }
  }
]
```

Output:
```
{
  "clients" : {
    "12" : "disabled",
    "35" : "enabled"
  }
}
```

//說明//
> @(3,clientId)解釋:
> @取的是價值,3(畫成樹去看),
> “*”是“1234”或“1235”,取其子節點的clientId的值。

# 5、嵌套轉換
//例子說明//
```
如果clientsActive是真實的,則執行轉換
@(2,clients)的值值:true 1 clientsActive 2
{
“Lucas公司”:{

“的clientId”:“LUCAS”的成員,

“指數”:1

},

“thunder”:{

“的clientId”:“THUNDER”,

“指數”:0
}
}
```
> 對他做“*”“clientId”:“clientIds [@(1,index)]”

Json Input:
```
{
  "clientsActive": true,
  "clients": {
    "Lucas": {
      "clientId": "LUCAS",
      "index": 1
    },
    "thunder": {
      "clientId": "THUNDER",
      "index": 0
    }
  }
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "clientsActive": {
        "true": {
          "@(2,clients)": {
            "*": {
              "clientId": "clientIds[@(1,index)]"
            }
          }
        }
      }
    }
  }
]
```

Output:
```
{
  "clientIds" : [ "THUNDER", "LUCAS" ]
}
```

# 6、轉義字符
Json Input:
```
{
  "@context": {
    "name": "https://blog.csdn.net/#name",
    "ingredient": "https://blog.csdn.net/#ingredient",
    "yield": "https://blog.csdn.net/#yield",
    "step": {
      "@id": "https://blog.csdn.net/",
      "@type": "xgd:integer"
    },
    "xgd": "https://mail.xgd.com/"
  }
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "\\@context": {
        "name": "&1.Name",
        "ingredient": "&1.Inputs",
        "yield": "\\@context.Makes",
        "*": "&1.&"
      }
    }
  }
]
```

Output:
```
{
  "@context" : {
    "Name" : "https://blog.csdn.net/#name",
    "Inputs" : "https://blog.csdn.net/#ingredient",
    "Makes" : "https://blog.csdn.net/#yield",
    "step" : {
      "@id" : "https://blog.csdn.net/",
      "@type" : "xgd:integer"
    },
    "xgd" : "https://mail.xgd.com/"
  }
}
```
# 7、利用&取關鍵值,替換原理,達到加後綴的目的
Json Input:
```
{
  "Rating": 1,
  "SecondaryRatings": {
    "Design": 4,
    "Price": 2,
    "RatingDimension3": 1
  }
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "Rating": "rating-primary",
      "SecondaryRatings": {
        "*": "rating-&"
      }
    }
  }
]
```

Output:
```
{
  "rating-primary" : 1,
  "rating-Design" : 4,
  "rating-Price" : 2,
  "rating-RatingDimension3" : 1
}
```

# 8、利用@實現分類取值 
Json Input:
```
{
  "enties": [
    {
      "type": "alpha",
      "data": "foo"
    },
    {
      "type": "beta",
      "data": "bar"
    },
    {
      "type": "alpha",
      "data": "zoo"
    }
  ]
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "enties": {
        "*": "@type[]"
      }
    }
  }
]
```

Output:
```
{
  "alpha" : [ {
    "type" : "alpha",
    "data" : "foo"
  }, {
    "type" : "alpha",
    "data" : "zoo"
  } ],
  "beta" : [ {
    "type" : "beta",
    "data" : "bar"
  } ]
}
```
> 說明按類型分類:如上alpha的數據就歸爲一類,beta的數據歸爲另一類。

# 9、轉換大小寫,值類型的轉換
Json Input:
```
{
  "x": [
    3,
    2,
    1,
    "go"
  ],
  "small": "small",
  "BIG": "BIG",
  "age": "18",
  "people": [
    {
      "firstName": "Bob",
      "lastName": "Smith",
      "address": {
        "state": null
      }
    },
    {
      "firstName": "Sterling",
      "lastName": "Archer"
    }
  ]
}
```

Jolt Spec:
```
[
  {
    "operation": "modify-default-beta",
    "spec": {
      "y": "=join(',',@(1,x))",
      "z": "=join(',',@(1,x))",
      "small_toUpper": "=toUpper(@(1,small))",
      "BIG_toLower": "=toLower(@(1,BIG))",
      "age_toInteger": "=toInteger(@(1,age))",
      "people": {
        "*": {
          "fullName": "=concat(@(1,firstName),'',@(1,lastName))",
          "address?": {
            "state": "Texas"
          }
        }
      }
    }
  }
]
```

Output:
```
{
  "x" : [ 3, 2, 1, "go" ],
  "small" : "small",
  "BIG" : "BIG",
  "age" : "18",
  "people" : [ {
    "firstName" : "Bob",
    "lastName" : "Smith",
    "address" : {
      "state" : "Texas"
    },
    "fullName" : "BobSmith"
  }, {
    "firstName" : "Sterling",
    "lastName" : "Archer",
    "fullName" : "SterlingArcher"
  } ],
  "y" : "3,2,1,go",
  "z" : "3,2,1,go",
  "small_toUpper" : "SMALL",
  "BIG_toLower" : "big",
  "age_toInteger" : 18
}
```
> 說明:如上所述,JOLT可以實現大小寫,值類型的轉換,轉換表達式還有很多,目前這些比較常用。

# 10、 “|”通配符
>  “|”表示“或”的邏輯,很容易理解,它只會匹配寫出的字符,如:

Json Input:
```
{
  "reserve": {
    "red_packet": {
      "quantity": "10",
      "color": "red",
      "Color": "green"
    }
  }
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "reserve": {
        "red_packet": {
          "quantity": "properties.quantity",
          "color|Color": "last_color"
        }
      }
    }
  }
]
```

Output:
```
{
  "properties" : {
    "quantity" : "10"
  },
  "last_color" : [ "red", "green" ]
}
```

# 11、去除一個字段:
Json Input:
```
{
  "_id": {
    "$old": "12245677777"
  },
  "id": 123
}
```

Jolt Spec:
```
[
  {
    "operation": "shift",
    "spec": {
      "_id": null,
      "*": "&"
    }
  }
]
```

Output:
```
{
  "id" : 123
}
```
> 說明:不需要那個字段直接賦null即可。

# 12、default轉換
(NOTE)注:default轉換比較簡單,對應的java類是Defaultr,主要作用是預先設置一些默認值,如果input中不存在該值,則使用默認值進行補齊。

Json Input:
```
{
  "reserve": {
    "number": 8,
    "red_packet": {
      "packet_id": "10000",
      "quantity": "10"
    }
  }
}
```

Jolt Spec:
```
[
   {
     "operation": "shift",
     "spec": {
       "reserve": {
         "number": "properties.counter",
         "red_packet": {
           "packet_id": "properties.packet_id",
           "quantity": "properties.quantity"
         }
       }
     }
      },
   {
     "operation": "default",
     "spec": {
       "type": "track",
       "event": "redpacket_noregister",
       "project": "coincola"
     }
   }
]
```

Output:
```
{
  "properties" : {
    "counter" : 8,
    "packet_id" : "10000",
    "quantity" : "10"
  },
  "event" : "redpacket_noregister",
  "type" : "track",
  "project" : "coincola"
}
```

//說明//
> 可以看到event、type、project在Input中是沒有的,我們在spec的相應位置設置了default值,在output中就展示了該值,其他值得設置也是類似的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章