Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CUEを使ったJSONテンプレート管理

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

 CUEを使ったJSONテンプレート管理

Avatar for Kazuma Arimura

Kazuma Arimura

December 02, 2022
Tweet

More Decks by Kazuma Arimura

Other Decks in Marketing & SEO

Transcript

  1. 2022 導入背景 GET /_search { "query": { "bool": { "should":

    [ { "match": { "name.first": { "query": "shay", "_name": "first" } } }, { "match": { "name.last": { "query": "banon", "_name": "last" } } } ], "filter": { "terms": { "name.last": [ "banon", "kimchy" ], "_name": "test" } } } } } Elasticsearch Query DSL • JSON型 • 複雑な条件の場合、ネストが深くなる • 条件の組み合わせによって、ブロックを挿入 する箇所を変えたいケースがある → クエリをコンポーネントで管理しつつ、 それらを組み合わせてクエリを組みたい
  2. 2022 導入背景 GET /_search { "query": { "bool": { "should":

    [ { "match": { "name.first": { "query": "shay", "_name": "first" } } }, { "match": { "name.last": { "query": "banon", "_name": "last" } } } ], "filter": { "terms": { "name.last": [ "banon", "kimchy" ], "_name": "test" } } } } } クエリビルダに求める条件 • 柔軟にJSONが構築できること • 複雑なクエリになっても可読性が高いこと • 学習コストが十分に低いこと • 型安全性が守れること ◦ ❌ interface{}の乱用
  3. 2022 CUE CUEとは? CUE is an open source data constraint

    language which aims to simplify tasks involving defining and using data. 特徴 • 基本的にJSONのsuperset • CUE自体はGoで記述された言語 ◦ 文法的にはJSON + Go • 値のvalidationが詳細に定義可能 • 各種IDEのサポートが豊富 • Goのpackageが公式で提供されている Logo from: https://cuelang.org/
  4. 2022 Data binding / validation Goのプログラムから変数のバインディング、また型・値のバリデーションが可能 min?: *0 | number

    // 0 if undefined max?: number & >min // must be strictly greater than min if defined. minmax.cue type minmax struct { Min int `json:"min"` Max int `json:"max"` } func main() { data := minmax{Min: 10, Max: 100} v := cuecontext.New().CompileBytes(template) filled := v.FillPath(cue.ParsePath(""), data) compiled, err := filled.MarshalJSON() } bind.go Structから 値をバインド
  5. 2022 Data binding / validation min?: *0 | number max?:

    number & >min minmax.cue func main() { data := minmax{Min: 10, Max: 100} v := cuecontext.New().CompileBytes(template) filled := v.FillPath(cue.ParsePath(""), data) compiled, err := filled.MarshalJSON() fmt.Printf("err: %v\njson:%s\n", err, compiled) } bind.go err: <nil> json:{"min":10,"max":100} out
  6. 2022 func main() { data := minmax{Min: 10, Max: 5}

    v := cuecontext.New().CompileBytes(template) filled := v.FillPath(cue.ParsePath(""), data) compiled, err := filled.MarshalJSON() fmt.Printf("err: %v\njson:%s\n", err, compiled) } bind.go Data binding / validation min?: *0 | number max?: number & >min minmax.cue 不正な値 err: cue: marshal error: max: invalid value 5 (out of bound >10) json: out
  7. 2022 Reduce boilerplate in your data list/mapを渡してイテレーション #name: { first:

    string last: string } #names: [... #name] #names: [ {first: "jiro", last: "sasaki"}, {first: "taro", last: "tanaka"}, ] attendees: [ for name in #names { {"name": "\(name.first) \(name.last)"} }, ] { "attendees": [ { "name": "jiro sasaki" }, { "name": "taro tanaka" } ] }
  8. 2022 Reduce boilerplate in your data 複数のCUEを結合 { term: {"name":

    "taro tanaka"} } term.cue { query: {} } query.cue { function_score: { query: {} random_score: {} } } function_score.cue
  9. 2022 Reduce boilerplate in your data 複数のCUEを結合 ※ FillPathで指定するValue同士は同一のcuecontextから生成される必要あり func

    mergeCue() { ctx := cuecontext.New() term := ctx.CompileBytes(termTemplate) query := ctx.CompileBytes(queryTemplate) score := ctx.CompileBytes(scoreTemplate) merged := query.FillPath(cue.ParsePath("query"), term) compiled, _ := merged.MarshalJSON() merged = score.FillPath(cue.ParsePath("function_score.query"), term) compiled, _ = merged.MarshalJSON() } merge.go
  10. 2022 パフォーマンス検証 他のJSON生成方法と比較した際のパフォーマンスについて検証 比較対象 • encoding/json • text/template シナリオ •

    1層のみのシンプルなJSON • 5層のネスト、リストありなJSON • testing.Bによるベンチマークでns/opとallocs/opを比較
  11. 2022 総合的な検討 encoding/json text/template cue-lang/cue 可読性(小規模) ◦ ◦ ◦ 可読性(大規模)

    ☓ ◦ ◦ 開発効率 △ ☓ ◦ 学習コスト ◦ △ △ 型安全性 ◦ ◦ ◦ 処理パフォーマンス ◦ ◦ ☓
  12. 2022 総合的な検討 クエリビルダに求める条件 • 柔軟にJSONが構築できること • 複雑なクエリになっても可読性が高いこと • 学習コストが十分に低いこと •

    型安全性が守れること encoding/json text/template cue-lang/cue 可読性(小規模) ◦ ◦ ◦ 可読性(大規模) ☓ △ ◦ 開発効率 △ ☓ ◦ 学習コスト ◦ △ △ 型安全性 ◦ ◦ ◦ 処理パフォーマンス ◦ ◦ ☓ WINNER👑 → 全て条件を満たした上で、複雑になった場合の可読性・開発効率から CUEを選択