Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
janzal committed Mar 21, 2024
1 parent 37fced7 commit dde66de
Show file tree
Hide file tree
Showing 13 changed files with 345 additions and 31 deletions.
23 changes: 22 additions & 1 deletion cmd/tsbs_generate_queries/databases/clickhouse/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ package clickhouse
import (
"time"

"github.com/timescale/tsbs/cmd/tsbs_generate_queries/uses/dea"
"github.com/timescale/tsbs/cmd/tsbs_generate_queries/uses/devops"
"github.com/timescale/tsbs/cmd/tsbs_generate_queries/utils"
"github.com/timescale/tsbs/pkg/query"
)

// BaseGenerator contains settings specific for ClickHouse.
type BaseGenerator struct {
UseTags bool
UseTags bool
PropertyAccessMode string
}

// GenerateEmptyQuery returns an empty query.ClickHouse.
Expand Down Expand Up @@ -42,3 +44,22 @@ func (g *BaseGenerator) NewDevops(start, end time.Time, scale int) (utils.QueryG

return devops, nil
}

// NewDEA creates a new devops use case query generator.
func (g *BaseGenerator) NewDEA(start, end time.Time, scale int) (utils.QueryGenerator, error) {
core, err := dea.NewCore(start, end, scale)

if err != nil {
return nil, err
}

devops := &DEA{
BaseGenerator: g,
Core: core,
}

return devops, nil
}

// ClickHouse understands and can compare time presented as strings of this format
const clickhouseTimeStringFormat = "2006-01-02 15:04:05"
108 changes: 108 additions & 0 deletions cmd/tsbs_generate_queries/databases/clickhouse/dea.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package clickhouse

import (
"fmt"
"strings"

"github.com/timescale/tsbs/cmd/tsbs_generate_queries/uses/dea"
"github.com/timescale/tsbs/pkg/query"
)

// Devops produces ClickHouse-specific queries for all the devops query types.
type DEA struct {
*dea.Core
*BaseGenerator
}

const (
Json string = "json"
Map string = "map"
)

func Must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}

func (d *DEA) getJSONProperty(key string) string {
return fmt.Sprintf("simpleJSONExtractRaw(propertiesJson, '%s')", key)
}

func (d *DEA) getMapProperty(key string) string {
return fmt.Sprintf("propertiesMap['%s']", key)
}

func (d *DEA) getProperty(key string) string {
switch d.PropertyAccessMode {
case Json:
return d.getJSONProperty(key)
case Map:
return d.getMapProperty(key)
default:
panic(fmt.Sprintf("unknown access mode %s", d.PropertyAccessMode))
}
}

func (d *DEA) getPropertyAlias(property string) string {
return fmt.Sprintf("a_%s", property)
}

func (d *DEA) getAliasedProperties(keys []string) []string {
aliasedProps := make([]string, len(keys))

for i := range keys {
aliasedProps[i] = fmt.Sprintf("%s as %s", d.getProperty(keys[i]), d.getPropertyAlias(keys[i]))
}

return aliasedProps
}

func (d *DEA) NestedWhere(qi query.Query, nProperties int) {
randomProperties, err := d.GetRandomProperties(4, dea.AvailableStrProperties)
panicIfErr(err)

selectClauses := strings.Join(d.getAliasedProperties(randomProperties), ", ")

whereClauses := fmt.Sprintf("%s = '%s' AND %s != '' AND (%s LIKE '%%%s%%' OR %s LIKE '%%%s')",
d.getPropertyAlias(randomProperties[0]),
Must(d.GetRandomPropertyValue(randomProperties[0])),
d.getPropertyAlias(randomProperties[1]),
d.getPropertyAlias(randomProperties[2]),
Must(d.GetRandomPropertyValue(randomProperties[2]))[2:6],
d.getPropertyAlias(randomProperties[3]),
Must(d.GetRandomPropertyValue(randomProperties[3]))[2:])

// GetRandomSubsetPerm - use this

sql := fmt.Sprintf(`
SELECT toStartOfHour(created_at) AS hour, %s FROM events WHERE %s
`, selectClauses, whereClauses)

humanLabel := "ClickHouse nested and dynamic"
humanDesc := fmt.Sprintf("%s: nested where query with dynamic data access", humanLabel)
d.fillInQuery(qi, humanLabel, humanDesc, dea.TableName, sql)
}

func (d *DEA) EventHistogram(qi query.Query) {
sql := fmt.Sprintf(`
SELECT
toDate(timestamp, 'Europe/Prague') as day,
uniq(user_id) as visitors,
count() as cnt
FROM events
WHERE
name LIKE 'package_changed_to%'
AND tenant_id = '57e8dcb8673eec55468b4567'
AND timestamp >= now() - INTERVAL 30 DAY
GROUP BY
day
ORDER BY
day WITH FILL
FROM toDate(now() - INTERVAL 30 DAY, 'Europe/Prague')
TO toDate(now(), 'Europe/Prague')
`)

d.fillInQuery(qi, "ClickHouse Event histogram", "Clickhouse Event histogram", dea.TableName, sql)
}
19 changes: 10 additions & 9 deletions cmd/tsbs_generate_queries/databases/clickhouse/devops.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,17 @@ func (d *Devops) getSelectClausesAggMetrics(aggregateFunction string, metrics []
return selectAggregateClauses
}

// ClickHouse understands and can compare time presented as strings of this format
const clickhouseTimeStringFormat = "2006-01-02 15:04:05"

// MaxAllCPU selects the MAX of all metrics under 'cpu' per hour for nhosts hosts,
// e.g. in pseudo-SQL:
//
// SELECT MAX(metric1), ..., MAX(metricN)
// FROM cpu
// WHERE
// (hostname = '$HOSTNAME_1' OR ... OR hostname = '$HOSTNAME_N')
// AND time >= '$HOUR_START'
// AND time < '$HOUR_END'
//
// (hostname = '$HOSTNAME_1' OR ... OR hostname = '$HOSTNAME_N')
// AND time >= '$HOUR_START'
// AND time < '$HOUR_END'
//
// GROUP BY hour
// ORDER BY hour
//
Expand Down Expand Up @@ -290,9 +289,11 @@ func (d *Devops) LastPointPerHost(qi query.Query) {
// SELECT minute, max(metric1), ..., max(metricN)
// FROM cpu
// WHERE
// (hostname = '$HOSTNAME_1' OR ... OR hostname = '$HOSTNAME_N')
// AND time >= '$HOUR_START'
// AND time < '$HOUR_END'
//
// (hostname = '$HOSTNAME_1' OR ... OR hostname = '$HOSTNAME_N')
// AND time >= '$HOUR_START'
// AND time < '$HOUR_END'
//
// GROUP BY minute
// ORDER BY minute ASC
//
Expand Down
7 changes: 6 additions & 1 deletion cmd/tsbs_generate_queries/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ package main

import (
"fmt"
"github.com/timescale/tsbs/pkg/query/config"
"os"
"time"

"github.com/timescale/tsbs/pkg/query/config"

"github.com/blagojts/viper"
"github.com/spf13/pflag"
"github.com/timescale/tsbs/cmd/tsbs_generate_queries/uses/dea"
"github.com/timescale/tsbs/cmd/tsbs_generate_queries/uses/devops"
"github.com/timescale/tsbs/cmd/tsbs_generate_queries/uses/iot"
"github.com/timescale/tsbs/cmd/tsbs_generate_queries/utils"
Expand All @@ -18,6 +20,9 @@ import (
)

var useCaseMatrix = map[string]map[string]utils.QueryFillerMaker{
"dea": {
dea.LabelNestedWhere: dea.NewNestedWhere(1),
},
"devops": {
devops.LabelSingleGroupby + "-1-1-1": devops.NewSingleGroupby(1, 1, 1),
devops.LabelSingleGroupby + "-1-1-12": devops.NewSingleGroupby(1, 1, 12),
Expand Down
82 changes: 82 additions & 0 deletions cmd/tsbs_generate_queries/uses/dea/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package dea

import (
"fmt"
"math/rand"
"time"

"github.com/timescale/tsbs/cmd/tsbs_generate_queries/uses/common"
"github.com/timescale/tsbs/pkg/query"
)

const (
TableName = "events"

LabelNestedWhere = "nested-where"
)

const (
UrlProperty = "url"
EmailProperty = "email"
NameProperty = "name"
PhoneProperty = "phone"
FavoriteNumberProperty = "age"
)

const (
NavigationEvent = "navigation"
)

var (
AvailableStrProperties = []string{UrlProperty, EmailProperty, NameProperty, PhoneProperty}
AvailableStrPropertyValues = map[string][]string{
UrlProperty: {"https://www.seznam.cz"},
EmailProperty: {"[email protected]"},
NameProperty: {"john doe"},
PhoneProperty: {"+420602303222"},
}
)

// Core is the common component of all generators for all systems.
type Core struct {
*common.Core
}

// NewCore returns a new Core for the given time range and cardinality
func NewCore(start, end time.Time, scale int) (*Core, error) {
c, err := common.NewCore(start, end, scale)
return &Core{Core: c}, err
}

type NestedWhereFiller interface {
NestedWhere(query.Query, int)
}

func (d *Core) GetRandomProperties(n int, properties []string) ([]string, error) {
if n < 1 {
return nil, fmt.Errorf("number of properties cannot be < 1; got %d", n)
}
if n > len(properties) {
return nil, fmt.Errorf("number of properties (%d) larger than total properties (%d)", n, len(properties))
}

randomNumbers, err := common.GetRandomSubsetPerm(n, len(properties))
if err != nil {
return nil, err
}

selectedProperties := make([]string, n)
for i, n := range randomNumbers {
selectedProperties[i] = properties[n]
}

return selectedProperties, nil
}

func (d *Core) GetRandomPropertyValue(property string) (string, error) {
if values, ok := AvailableStrPropertyValues[property]; ok {
return values[rand.Intn(len(values))], nil
} else {
return "", fmt.Errorf("no values for %s", property)
}
}
31 changes: 31 additions & 0 deletions cmd/tsbs_generate_queries/uses/dea/nested_where.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dea

import (
"github.com/timescale/tsbs/cmd/tsbs_generate_queries/uses/common"
"github.com/timescale/tsbs/cmd/tsbs_generate_queries/utils"
"github.com/timescale/tsbs/pkg/query"
)

// NestedWhere contains info for filling in avg load queries.
type NestedWhere struct {
core utils.QueryGenerator
}

// NewNestedWhere creates a new avg load query filler.
func NewNestedWhere(scale int) utils.QueryFillerMaker {
return func(core utils.QueryGenerator) utils.QueryFiller {
return &NestedWhere{
core: core,
}
}
}

// Fill fills in the query.Query with query details.
func (i *NestedWhere) Fill(q query.Query) query.Query {
fc, ok := i.core.(NestedWhereFiller)
if !ok {
common.PanicUnimplementedQuery(i.core)
}
fc.NestedWhere(q, 1)
return q
}
Loading

0 comments on commit dde66de

Please sign in to comment.