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

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

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

Kazuma Arimura

December 02, 2022
Tweet

More Decks by Kazuma Arimura

Other Decks in Marketing & SEO

Transcript

  1. CUEを使った
    JSONテンプレート管理
    US@Tokyo ML/Search team
    @pakio
    2022/12/02 - mercari.go #20

    View Slide

  2. 2022
    Agenda
    ● 導入背景
    ● CUEについて
    ○ JSONビルダとしての利用事例
    ● 他の生成方法との比較検討
    ● まとめ

    View Slide

  3. 2022
    背景

    View Slide

  4. 2022
    導入背景
    現在のMercari USの検索周りシステム構成(概略)
    Microservices
    BFF

    search team
    Search Service Primary
    Search Engine
    Elasticsearch

    View Slide

  5. 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型
    ● 複雑な条件の場合、ネストが深くなる
    ● 条件の組み合わせによって、ブロックを挿入
    する箇所を変えたいケースがある
    → クエリをコンポーネントで管理しつつ、
    それらを組み合わせてクエリを組みたい

    View Slide

  6. 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{}の乱用

    View Slide

  7. 2022
    CUE

    View Slide

  8. 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/

    View Slide

  9. 2022
    社内事例 - Kubernetes Configuration Management with CUE
    https://engineering.mercari.com/en/blog/entry/20220127-kubernetes-configuration-management-with-cue/

    View Slide

  10. 2022
    JSONビルダとしてのCUE

    View Slide

  11. 2022
    JSONビルダとしてのCUE
    JSON生成までの手順
    1. JSONのテンプレートを.cue形式で記述
    2. Goのプログラム内で読み込み、CompileBytes()またはCompileString()でcue.Value形式にコンパイル
    3. (必要に応じて)プログラムから値のバインディング/マージ等の操作
    4. JSON等用途に応じた形式で出力

    View Slide

  12. 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から
    値をバインド

    View Slide

  13. 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:
    json:{"min":10,"max":100}
    out

    View Slide

  14. 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

    View Slide

  15. 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"
    }
    ]
    }

    View Slide

  16. 2022
    Reduce boilerplate in your data
    複数のCUEを結合
    {
    term: {"name": "taro tanaka"}
    }
    term.cue
    {
    query: {}
    }
    query.cue
    {
    function_score: {
    query: {}
    random_score: {}
    }
    }
    function_score.cue

    View Slide

  17. 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

    View Slide

  18. 2022
    CUE
    その他サポートされているオペレーション
    :
    ● Ifによる条件分岐
    ● 各種論理演算子・算術演算(math packageの一部)
    ● len()を用いた配列長判定
    ● nullが渡された場合のデフォルト値定義

    View Slide

  19. 2022
    比較/検討

    View Slide

  20. 2022
    パフォーマンス検証
    他のJSON生成方法と比較した際のパフォーマンスについて検証
    比較対象
    ● encoding/json
    ● text/template
    シナリオ
    ● 1層のみのシンプルなJSON
    ● 5層のネスト、リストありなJSON
    ● testing.Bによるベンチマークでns/opとallocs/opを比較

    View Slide

  21. 2022
    検証結果
    → us単位なので許容範囲なものの、かなり低速
    かつencoding/json, text/templateと比較して、複雑度の増加に対する速度の低下が顕著

    View Slide

  22. 2022
    総合的な検討
    encoding/json text/template cue-lang/cue
    可読性(小規模) ○ ○ ○
    可読性(大規模) ☓ ○ ○
    開発効率 △ ☓ ○
    学習コスト ○ △ △
    型安全性 ○ ○ ○
    処理パフォーマンス ○ ○ ☓

    View Slide

  23. 2022
    総合的な検討
    クエリビルダに求める条件
    ● 柔軟にJSONが構築できること
    ● 複雑なクエリになっても可読性が高いこと
    ● 学習コストが十分に低いこと
    ● 型安全性が守れること
    encoding/json text/template cue-lang/cue
    可読性(小規模) ○ ○ ○
    可読性(大規模) ☓ △ ○
    開発効率 △ ☓ ○
    学習コスト ○ △ △
    型安全性 ○ ○ ○
    処理パフォーマンス ○ ○ ☓
    WINNER👑
    → 全て条件を満たした上で、複雑になった場合の可読性・開発効率から CUEを選択

    View Slide

  24. 2022
    まとめ

    View Slide

  25. 2022
    まとめ
    ● Mercari USの検索ではElasticsearch向けのJSONビルダとしてCUEを利用している
    ● シンタックスハイライトやIDEによるオートコンプリートなどの恩恵を受けた効率的な開発を実現
    ● ただし、パフォーマンスについての懸念が若干あるため、ユースケース毎に検証は必要そう

    View Slide

  26. 2022
    Thanks!

    View Slide