Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hamilton + AWS #768

Merged
merged 4 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions examples/aws/lambda/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM public.ecr.aws/lambda/python:3.11

COPY requirements.txt ./
RUN pip install -r requirements.txt

tyapochkin marked this conversation as resolved.
Show resolved Hide resolved
ENV HAMILTON_TELEMETRY_ENABLED=false

COPY app ./app

CMD ["app.lambda_handler.lambda_handler"]
67 changes: 67 additions & 0 deletions examples/aws/lambda/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Deploy Hamilton in AWS Lambda

[AWS Lambda](https://aws.amazon.com/lambda/) - serverless computation service in AWS.

Here we have an example how to deploy "hello-world" AWS Lambda with Hamilton functions.
This example is based on the official instruction: https://docs.aws.amazon.com/lambda/latest/dg/python-image.html#python-image-instructions

0. Set up AWS CLI: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-quickstart.html

1. Docker image build:

```shell
docker build --platform linux/amd64 -t aws-lambda-hamilton .
```

2. Local tests:

```shell
docker run -p 9000:8080 aws-lambda-hamilton
```

```shell
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"body": {"columns":["signups","spend"],"index":[0,1,2,3,4,5],"data":[[1,10],[10,10],[50,20],[100,40],[200,40],[400,50]]}}'
```

3. Create AWS ECR repository:


```shell
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
```

```shell
aws ecr create-repository --repository-name aws-lambda-hamilton --region us-east-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
```

4. Deploy image to AWS ECR:

```shell
docker tag aws-lambda-hamilton 111122223333.dkr.ecr.us-east-1.amazonaws.com/aws-lambda-hamilton:latest
```

```shell
docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/aws-lambda-hamilton:latest
```

4.5. Create simple AWS Lambda role (if needed):

```shell
aws iam create-role --role-name lambda-ex --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}'
```

5. Create AWS Lambda

```shell
aws lambda create-function \
--function-name aws-lambda-hamilton \
--package-type Image \
--code ImageUri=111122223333.dkr.ecr.us-east-1.amazonaws.com/aws-lambda-hamilton:latest \
--role arn:aws:iam::111122223333:role/lambda-ex
```

6. Test AWS Lambda

```shell
aws lambda invoke --function-name aws-lambda-hamilton --cli-binary-format raw-in-base64-out --payload '{"body": {"columns":["signups","spend"],"index":[0,1,2,3,4,5],"data":[[1,10],[10,10],[50,20],[100,40],[200,40],[400,50]]}}' response.json
```
Empty file.
38 changes: 38 additions & 0 deletions examples/aws/lambda/app/functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pandas as pd

from hamilton.function_modifiers import extract_columns


@extract_columns("spend", "signups")
def raw_table(input_table: pd.DataFrame) -> pd.DataFrame:
return input_table


def avg_3wk_spend(spend: pd.Series) -> pd.Series:
"""Rolling 3 week average spend."""
return spend.rolling(3).mean()


def spend_per_signup(spend: pd.Series, signups: pd.Series) -> pd.Series:
"""The cost per signup in relation to spend."""
return spend / signups


def spend_mean(spend: pd.Series) -> float:
"""Shows function creating a scalar. In this case it computes the mean of the entire column."""
return spend.mean()


def spend_zero_mean(spend: pd.Series, spend_mean: float) -> pd.Series:
"""Shows function that takes a scalar. In this case to zero mean spend."""
return spend - spend_mean


def spend_std_dev(spend: pd.Series) -> float:
"""Function that computes the standard deviation of the spend column."""
return spend.std()


def spend_zero_mean_unit_variance(spend_zero_mean: pd.Series, spend_std_dev: float) -> pd.Series:
"""Function showing one way to make spend have zero mean and unit variance."""
return spend_zero_mean / spend_std_dev
24 changes: 24 additions & 0 deletions examples/aws/lambda/app/lambda_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pandas as pd

from hamilton import driver

from . import functions


def lambda_handler(event, context):

df = pd.DataFrame(**event["body"])

dr = driver.Driver({}, functions)

output_columns = [
"spend",
"signups",
"avg_3wk_spend",
"spend_per_signup",
"spend_zero_mean_unit_variance",
]

df_result = dr.execute(output_columns, inputs={"input_table": df})

return {"statusCode": 200, "body": df_result.to_json(orient="split")}
2 changes: 2 additions & 0 deletions examples/aws/lambda/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pandas
sf-hamilton