Skip to content
chalk-aiPublic

About

Go client for Chalk

Topics

Resources

Security policy

Stars

12 stars

Watchers

5 watching

Forks

Latest commit

 

History

1,729 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go Reference Test

Go Chalk

The official Chalk client library.

Usage

Installation

Make sure your project is using Go modules (it will have a go.mod file in its root if it already is):

go mod init <module-path>

Then reference chalk-go in your Go program:

import (
    "github.com/chalk-ai/chalk-go"
)

Run any of the normal go commands (build/install/test). The Go toolchain will resolve and fetch the chalk-go module automatically.

Alternatively, you can explicitly add the dependency:

go get -u github.com/chalk-ai/chalk-go

This library requires Go 1.24.6 or later.

Codegen

Chalk generates Go structs from your Python feature definitions, which makes it easy to use your features from Go.

Run the codegen command inside your Chalk project to generate a file containing your generated structs, then copy that file into your Go project.

chalk codegen go --out=<OUTPUT_FILEPATH>

You can read more in the CLI docs.

Connect to Chalk

Create a client using NewClient. The returned client gets its configuration from the first available source in this order:

  1. Overrides configured by passing a *chalk.ClientConfig:
    client, err := chalk.NewClient(
        ctx,
        &chalk.ClientConfig{
            ClientId:      "id-89140a6614886982a6782106759e30",
            ClientSecret:  "sec-b1ba98e658d7ada4ff4c7464fb0fcee65fe2cbd86b3dd34141e16f6314267b7b",
            ApiServer:     "https://api.chalk.ai",
            EnvironmentId: "qa",
            Branch:        "jorges-december",
        },
    )
  2. Environment variables:
    • CHALK_ACTIVE_ENVIRONMENT
    • CHALK_API_SERVER
    • CHALK_CLIENT_ID
    • CHALK_CLIENT_SECRET
    client, err := chalk.NewClient(ctx)
  3. The file ~/.chalk.yml, which is created and updated when you run chalk login:
    client, err := chalk.NewClient(ctx)

gRPC Client

To use gRPC as the underlying protocol for communication with Chalk:

// Create a client
client, err := chalk.NewGRPCClient(
	ctx,
	&chalk.GRPCClientConfig{Branch: "my-branch"},
)

// Online query
var users []User
res, err := client.OnlineQueryBulk(
	ctx,
	chalk.OnlineQueryParams{}.
		WithInput(Features.User.Id, []string{"u273489056"}).
		WithInput(Features.User.Transactions, [][]Transaction{
			{
				{Id: utils.ToPtr("txn8f76"), Amount: utils.ToPtr(13.23)},
				{Id: utils.ToPtr("txn546d"), Amount: utils.ToPtr(48.95)},
			},
		}).
		WithOutputs(Features.User.Id, Features.User.WeightedScore),
)
if err != nil {
	return errors.Wrap(err, "querying weighted score")
}
if err = res.UnmarshalInto(&users); err != nil {
	return errors.Wrap(err, "unmarshalling into users")
}
fmt.Printf("user %s has weighted score %v\n", users[0].Id, users[0].WeightedScore)


// Multi-namespace online query
type underwriting struct {
	User
	Loan
}

res, err := client.OnlineQueryBulk(
    context.Background(),
    chalk.OnlineQueryParams{}.
        WithInput(Features.User.Id, []string{"u273489056"}).
        WithInput(Features.Loan.Id, []string{"l273489056"}).
        WithOutputs(
            Features.User.Id,
            Features.User.WeightedScore,
            Features.Loan.Id,
            Features.Loan.ApprovalStatus,
        ),
)
if err != nil {
	return errors.Wrap(err, "querying weighted score and loan approval status")
}

var root []underwriting
if err = res.UnmarshalInto(&root); err != nil {
	return errors.Wrap(err, "unmarshalling into underwriting")
}
fmt.Printf("user %s has weighted score %v\n", root[0].User.Id, root[0].User.WeightedScore)
fmt.Printf("loan %s has approval status %v\n", root[0].Loan.Id, root[0].Loan.ApprovalStatus)

Online Query

Query online features using the generated feature structs. Access results in the returned object or by passing a pointer to a variable with the correct type.

user := User{}
_, err = client.OnlineQuery(
    context.Background(),
    chalk.OnlineQueryParams{}.
        WithInput(Features.User.Id, "u273489057").
        WithInput(Features.User.Transactions, []Transaction{
            {Id: utils.ToPtr("sd8f76"), Amount: utils.ToPtr(13.23)},
            {Id: utils.ToPtr("jk546d"), Amount: utils.ToPtr(48.95)},
        }).
        WithOutputs(Features.User.Id, Features.User.LastName),
    &user,
)

Named Queries

If your deployment contains named queries, you can specify a query name instead of outputs when making a query.

user := User{}
_, err = client.OnlineQuery(
    context.Background(),
    chalk.OnlineQueryParams{}.
        WithInput(Features.User.Id, "u273489057").
        WithQueryName("user_underwriting_features"),
    &user,
)

Offline Query

When executing an offline query, a dataset is returned and can be downloaded as parquet files using the DownloadData method.

res, err := client.OfflineQuery(
    context.Background(),
    chalk.OfflineQueryParams{}.
        WithInput(Features.User.Id, []any{...}).
        WithOutputs(Features.User),
)
if err != nil {
    return err
}

err = res.Revisions[0].DownloadData(<FILE_DIRECTORY>)

Upload Features

Chalk allows you to synchronously persist features directly to your online and offline stores.

res, err := client.UploadFeatures(
    context.Background(),
    chalk.UploadFeaturesParams{
        Inputs: map[any]any{
            Features.User.Id: []string{"user-1", "user-2"},
            "user.last_name": []string{"Borges", "Paris"},
        },
    },
)

Update Aggregates

Note: This method is available only when using the gRPC client. See gRPC Client for more information.

You can easily update your windowed aggregation feature values with UpdateAggregates. For example, with this feature definition:

@features
class User:
    id: str
    txns: "DataFrame[Transaction]"
    txn_amount_total: Windowed[int] = windowed(
        "30d",
        "90d",
        materialization={
            "bucket_duration": "1d",
        },
        expression=_.txns[_.amount].sum(),
    )

@features
class Transaction:
    id: Primary[str]
    amount: float
    user_id: str

Then to update the txn_amount_total feature, you would upload features corresponding to that aggregation:

res, err := client.UpdateAggregates(
    context.Background(),
    chalk.UpdateAggregatesParams{
        Inputs: map[any]any{
            "transaction.id": []string{"txn-1", "txn-2"},
            "transaction.user_id": []string{"user-1", "user-2"},
            "transaction.amount": []float64{100.0, 200.0},
            "transaction.__chalk_observed_at__": []time.Time{time.Now(), time.Now()},
        },
    },
)

Note that if you have an explicit FeatureTime feature specified, you can provide that in place of the __chalk_observed_at__ column.

Querying against a branch

To query against a branch, create a Client with Branch specified, then make queries using that client.

client, err := chalk.NewClient(
	context.Background(),
	&chalk.ClientConfig{
		Branch:        "jorges-december",
	},
)

Configuring Logging

By default, Chalk logs error messages only (which are sent to stderr). Configure default logging using the global DefaultLeveledLogger variable:

chalk.DefaultLeveledLogger = &chalk.StdOutLeveledLogger{
    Level: chalk.LevelInfo,
}

It's also possible to use non-Chalk leveled loggers. Chalk expects loggers to comply with the following interface:

type LeveledLogger interface {
    Debugf(format string, v ...interface{})
    Errorf(format string, v ...interface{})
    Infof(format string, v ...interface{})
    Warnf(format string, v ...interface{})
}

Some loggers like Logrus and Zap's SugaredLogger support this interface natively, so it's possible to set DefaultLeveledLogger to a *logrus.Logger or *zap.SugaredLogger directly. To use other loggers, you may need a shim layer.

Client Side Tracing

Set TracerProvider to trace OnlineQueryBulk request preparation, the RPC, and result decoding with OpenTelemetry. Tracing is off by default.

client, err := chalk.NewGRPCClient(ctx, &chalk.GRPCClientConfig{
    TracerProvider: otel.GetTracerProvider(),
    Tracing: &chalk.TracingOptions{
        Transport: true, // Optional transport diagnostics
    },
})

Use your configured OpenTelemetry provider, including the Datadog OpenTelemetry bridge. Configure the provider's exporter in your application to send spans to your tracing backend. For distributed trace propagation, add a Connect interceptor such as otelconnect through GRPCClientConfig.Interceptors.

TracingOptions.Transport adds chalk.online_query_bulk.http spans with connection, request and response timings, connection reuse, and TCP RTT on Linux when available. Diagnostics are only collected when the RPC span is recording. Response waiting includes server processing; TCP RTT measures the connected peer. Response read/decode timing includes response and trailer waits plus protobuf decoding. Arrow decoding is traced separately. Spans include query metadata and payload sizes, never credentials or feature values.

Querying for expressions

With the gRPC client, you can also query expressions that are not part of your feature set.

client, err := chalk.NewGRPCClient(ctx)
result, err := client.OnlineQueryBulk(
    ctx,
    chalk.OnlineQueryParams{}.
        WithInput("user.id", []int{1}).
        WithOutputs("user.id").
        WithOutputExprs(
            expr.FunctionCall(
                "jaccard_similarity",
                expr.Col("name"),
                expr.Col("email"),
            ).
                As("name_email_sim"),
            expr.DataFrame("transactions").
                Filter(expr.Col("amount").Gt(expr.Float(400000.0))).
                Agg("count").
                As("user_transaction_count"),
        ),
)
row, err := result.GetRow(0)
for feature, value := range row.Features {
    fmt.Printf("Feature: %s, Value: %+v\n", feature, value.Value)
}

This API allows for computing both scalar expressions (like jaccard_similarity above) as well as aggregations over DataFrames (like user_transaction_count above).

The script above prints:

Feature: user.id, Value: 1
Feature: name_email_sim, Value: 0.4375
Feature: user_transaction_count, Value: 0

Note that the .As(...) method gives the name of the expression in the returned result.

Contributing

We'd love to accept your patches. If you submit a pull request, please keep the following guidelines in mind:

  1. Fork the repo, develop and test your code changes.
  2. Ensure your code adheres to the existing style.
  3. Ensure that your code has an appropriate set of tests that pass.
  4. Submit a pull request.

Development

Clone the Git repo from github.com/chalk-ai/chalk-go.

  1. All patches must be go fmt compatible.
  2. All types, structs, and functions should be documented.

Testing

To execute the tests: go test ./.... Ensure all tests pass.

License

Apache 2.0 - See LICENSE for more information.

About

Go client for Chalk

Topics

Resources

Security policy

Stars

12 stars

Watchers

5 watching

Forks

Releases

Used by

Contributors

Languages

⌂ 换网址