{"id":330359,"date":"2022-03-05T15:01:16","date_gmt":"2022-03-05T15:01:16","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=330359"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=330359","title":{"rendered":"<span>\u041f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u0430 \u0438\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Google Cloud Functions \u0438 AWS Lambda\/Snowflake<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u0441\u0447\u0435\u0442\u0447\u0438\u043a\u0438 \u0432\u0435\u0431 \u0438\u043b\u0438 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Google Analytics \u0438\u043b\u0438 AppsFlyer? \u041d\u0430 \u0441\u0430\u0439\u0442 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0438\u0445 \u043a\u043e\u0434\u044b \u0438\u043b\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 SDK. \u041f\u043e\u0442\u043e\u043c \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f http \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f Google Analytics \u0432 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442: <code>https:\/\/analytics.google.com\/g\/collect?v=2&amp;tid=G-XXXXXXXXXX&amp;cid=1415663337.1642776362&amp;en=order<\/code> , \u0433\u0434\u0435:<\/p>\n<ul>\n<li>\n<p><strong>tid<\/strong> &#8212; \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043f\u043e\u0442\u043e\u043a\u0430(\u0441\u0447\u0435\u0442\u0447\u0438\u043a\u0430)<\/p>\n<\/li>\n<li>\n<p><strong>cid<\/strong> &#8212; \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430<\/p>\n<\/li>\n<li>\n<p><strong>en<\/strong> &#8212; \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/p>\n<\/li>\n<\/ul>\n<p>\u0423 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u0441\u0447\u0435\u0442\u0447\u0438\u043a\u043e\u0432\/\u043f\u0438\u043a\u0441\u0435\u043b\u0435\u0439 \u0435\u0441\u0442\u044c \u043c\u0438\u043d\u0443\u0441\u044b:<\/p>\n<ul>\n<li>\n<p>\u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0441\u0435\u0442\u0438\u0442\u0435\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0430\u043d\u043e\u043d\u0438\u043c\u0430\u0439\u0437\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442 \u0442\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b;  <\/p>\n<\/li>\n<li>\n<p>\u0438\u0445 \u0441\u043b\u043e\u0436\u043d\u043e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0441\u0435\u0431\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u0447\u0435\u0442\u0447\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0448\u0430\u0442\u044c \u044d\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u0421\u0447\u0435\u0442\u0447\u0438\u043a \u0432\u0441\u0442\u0440\u043e\u0438\u043c \u0432 PowerBI \u043e\u0442\u0447\u0435\u0442\u044b. \u041d\u043e \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432, \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u043d\u0430 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u0435, \u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0438 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445\u00a0 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0443. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0434\u0432\u0435 \u0442\u043e\u0447\u043a\u0438 \u0441\u0431\u043e\u0440\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439: Google Cloud Function, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432 Google BigQuery, \u0438 Amazon Lambda Functions \u0441 \u0437\u0430\u043f\u0438\u0441\u044c\u044e \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Snowflake.<\/p>\n<p><strong>1) <\/strong>\u00a0\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 <a href=\"https:\/\/console.cloud.google.com\/functions\/add\" rel=\"noopener noreferrer nofollow\"><u>Google Cloud Function &#8212; Create function<\/u><\/a>. \u0423\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0442\u0440\u0438\u0433\u0433\u0435\u0440 <strong>HTTP<\/strong>, \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0433\u0430\u043b\u043e\u0447\u043a\u0430 \u043d\u0430\u043f\u0440\u043e\u0442\u0438\u0432 <strong>Require authentication<\/strong>. \u0416\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0447\u0442\u043e\u0431\u044b <strong>Region<\/strong> \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u043b \u0441 \u0440\u0435\u0433\u0438\u043e\u043d\u043e\u043c \u0432 \u0432\u0430\u0448\u0435\u043c \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0435 \u0432 BigQuery.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0fd\/f7a\/299\/0fdf7a299f74f6fcdb6c32c554219f24.png\" width=\"623\" height=\"974\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0fd\/f7a\/299\/0fdf7a299f74f6fcdb6c32c554219f24.png\"\/><figcaption><\/figcaption><\/figure>\n<p><strong>URL<\/strong> \u043d\u0430 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u0435 \u2013 \u044d\u0442\u043e \u0442\u043e\u0442 \u0430\u0434\u0440\u0435\u0441, \u043a\u0443\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f.\u00a0\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>https:\/\/us-central1-project-name.cloudfunctions.net\/powerbi<\/code>\u00a0<\/p>\n<p>\u0427\u0435\u0440\u0435\u0437 GET \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043d\u0430 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c referrer. \u0412 \u043d\u0430\u0448\u0435\u043c \u0436\u0435 \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u0447\u0435\u0442\u0430 \u0432 PowerBI \u0438 \u0438\u043c\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. \u0422\u043e\u0433\u0434\u0430 \u0430\u0434\u0440\u0435\u0441 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u0438\u0434: <code>https:\/\/us-central1-project-name.cloudfunctions.net\/powerbi?report=MyReport&amp;page=Page1<\/code>  <\/p>\n<p><strong>2)<\/strong> \u0414\u0430\u043b\u0435\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c Python. \u0412 \u0444\u0430\u0439\u043b\u0435 <strong>requirements.txt<\/strong> \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442:  <\/p>\n<pre><code>requests>=2.27.1 google.cloud>=0.34.0 google-cloud-bigquery>=2.32.0<\/code><\/pre>\n<p>\u0412 \u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <strong>config.py<\/strong> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:\u00a0<\/p>\n<pre><code># id \u0447\u0430\u0442\u0430 \u0432 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u0435 \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0438. \u0447\u0442\u043e\u0431\u044b \u0443\u0437\u043d\u0430\u0442\u044c \u0441\u0432\u043e\u0439 id - \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0431\u043e\u0442\u0443 @userinfobot  tg_chat_id = 'XXXXXXX'  # \u0442\u043e\u043a\u0435\u043d \u0431\u043e\u0442\u0430. \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0431\u043e\u0442\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0432 @BotFather tg_bot_token = 'YYYYYYY:YYYYYYYYYYYYYYYYYYYYYYYYYY'  # \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 BigQuery \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \u0415\u0435 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0437\u0430\u0440\u0430\u043d\u0435\u0435. bq_table_name = 'project-name.dataset.powerbi_views'<\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b <strong>main.py<\/strong>:\u00a0<\/p>\n<pre><code>import datetime import requests from google.cloud import bigquery from config import tg_chat_id, tg_bot_token, bq_table_name   def main(request, report='', page='', ip='', user_agent=''):     if 'report' in request.args:         report = request.args['report']     if 'page' in request.args:         page = request.args['page']        #for headers in request.headers:  header = header + str(headers)  # \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438     ip = request.headers['X-Forwarded-For']     user_agent = request.headers['User-Agent']       if report != '':         return stream_bq(report, page, ip, user_agent)     else:         url = 'https:\/\/api.telegram.org\/bot' + tg_bot_token + '\/sendMessage?chat_id=' + tg_chat_id + '&amp;text=google cloud functions powerbi error: event without parameters received'         response = requests.get(url)         return 'event without parameters received'        def stream_bq(report, page, ip, user_agent):     bq_client = bigquery.Client()     bq_table = bq_client.get_table(bq_table_name)     row = [{'report': report,             'page': page,             'ip': ip,             'timestamp': datetime.datetime.utcnow(),             'user_agent': user_agent  }]     bq_client.insert_rows(bq_table, row)     return 'ok'<\/code><\/pre>\n<p>\u041d\u0430\u0436\u0438\u043c\u0430\u0435\u043c <strong>Deploy<\/strong>, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443: \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 <strong>URL<\/strong> \u0438\u0437 \u043f\u0443\u043d\u043a\u0442\u0430 1. \u0414\u043e\u043b\u0436\u043d\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u201c\u043e\u043a\u201d. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u2013 \u0438\u0449\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 <strong>Logs.<\/strong>  <\/p>\n<p><strong>3)<\/strong> \u0412 BigQuery \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c  \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a7d\/38b\/428\/a7d38b42825fb270f1812662d2495372.png\" width=\"843\" height=\"57\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a7d\/38b\/428\/a7d38b42825fb270f1812662d2495372.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043e\u0431\u043e\u0433\u0430\u0442\u0438\u043c \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435:<\/p>\n<p><strong>3.1)<\/strong> \u041f\u043e <strong>ip<\/strong>\u00a0 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0441\u0442\u0440\u0430\u043d\u0443, \u0433\u043e\u0440\u043e\u0434, \u043f\u043e\u0447\u0442\u043e\u0432\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0434\u0430\u043d\u043d\u044b\u0435 <a href=\"https:\/\/cloud.google.com\/blog\/products\/data-analytics\/geolocation-with-bigquery-de-identify-76-million-ip-addresses-in-20-seconds\" rel=\"noopener noreferrer nofollow\"><u>GeoLite2 Free Geolocation Data<\/u><\/a>:  <\/p>\n<pre><code>SELECT *  FROM ( SELECT ip FROM `project-name.dataset.powerbi_views` GROUP BY ip ) AS q  CROSS JOIN (    SELECT country_name, network, network_bin, city_name, postal_code, mask    FROM `fh-bigquery.geocode.201806_geolite2_city_ipv4_locs`  ) AS g  WHERE network_bin = NET.IP_FROM_STRING(ip) &amp; NET.IP_NET_MASK(4, mask)<\/code><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d25\/2d0\/cf4\/d252d0cf4df6a6aa640e5ddb58532b53.png\" width=\"616\" height=\"61\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d25\/2d0\/cf4\/d252d0cf4df6a6aa640e5ddb58532b53.png\"\/><figcaption><\/figcaption><\/figure>\n<p><strong>3.2)<\/strong> \u0418\u0437 <strong>user_agent<\/strong> \u0432\u044b\u0434\u0435\u043b\u0438\u043c\u00a0 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f JS \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/github.com\/woothee\/woothee-js\/tree\/master\/release\" rel=\"noopener noreferrer nofollow\"><u>woothee<\/u><\/a>:<\/p>\n<pre><code>CREATE OR REPLACE FUNCTION `project-name.dataset.decode_user_agent`(ua STRING)    RETURNS STRING    LANGUAGE js AS \"\"\"  return JSON.stringify(woothee.parse(ua));    \"\"\"OPTIONS(library=\"gs:\/\/project-name-bucket\/woothee.js\");<\/code><\/pre>\n<pre><code>SELECT JSON_VALUE(json, '$.os') AS os, JSON_VALUE(json, '$.name') AS browser, json, user_agent, FROM  (    SELECT user_agent, `bproject-name.dataset.decode_user_agent`(user_agent) AS json    FROM `bi-analytics-318415.Others.powerbi_views`    GROUP BY user_agent )<\/code><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/53c\/637\/95a\/53c63795aa625ebe9606d69c9a42ce86.png\" width=\"828\" height=\"58\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/53c\/637\/95a\/53c63795aa625ebe9606d69c9a42ce86.png\"\/><figcaption><\/figcaption><\/figure>\n<p><strong>3.3)<\/strong> \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0437\u043d\u0430\u0435\u043c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043c\u043e\u0442\u0440\u044f\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438, \u043d\u043e \u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443. \u041c\u043e\u0436\u043d\u043e \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0447\u0435\u0442\u043d\u043e\u0441\u0442\u044c \u043d\u0430 \u0441\u0432\u043e\u0439 \u0432\u043a\u0443\u0441.<\/p>\n<p><strong>4)<\/strong> \u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448 \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0432 PowerBI. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u2013 \u043d\u0430\u0448\u0438\u043c URL:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f34\/ef8\/1c8\/f34ef81c87347cb5c3bb049b1bb97c4a.png\" width=\"601\" height=\"116\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f34\/ef8\/1c8\/f34ef81c87347cb5c3bb049b1bb97c4a.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0417\u0430\u0442\u0435\u043c \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u044d\u0442\u0443 \u043a\u043e\u043b\u043e\u043d\u043a\u0443 \u0441\u043f\u0440\u0430\u0432\u0430 \u0438 \u0432 \u043c\u0435\u043d\u044e <strong>Column tools<\/strong> \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c <strong>Data category<\/strong> = <strong>Image URL<\/strong>:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/247\/47e\/b1a\/24747eb1aa9728682096588c4820ce48.png\" width=\"246\" height=\"110\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/247\/47e\/b1a\/24747eb1aa9728682096588c4820ce48.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043e\u0442\u0447\u0435\u0442 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u201c\u0442\u0430\u0431\u043b\u0438\u0446\u0430\u201d \u0441 \u044d\u0442\u043e\u0439 \u043a\u043e\u043b\u043e\u043d\u043a\u043e\u0439 \u0433\u0434\u0435-\u043d\u0438\u0431\u0443\u0434\u044c \u0432 \u043c\u0430\u043b\u043e\u0437\u0430\u043c\u0435\u0442\u043d\u043e\u043c \u0443\u0433\u043b\u0443 \u043e\u0442\u0447\u0435\u0442\u0430. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0435\u0433\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u0443\u0445\u043e\u0434\u0438\u0442\u044c http \u0437\u0430\u043f\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0447\u0435\u0440\u0435\u0437 Cloud Functions \u0431\u0443\u0434\u0435\u0442 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 BigQuery. <strong>\u041d\u0430\u0448 \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0433\u043e\u0442\u043e\u0432!<\/strong><\/p>\n<p><strong>5) <\/strong>\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u044b\u0442\u044c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u043c \u043e\u0434\u043d\u0438\u043c \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u043c \u0432\u0435\u043d\u0434\u043e\u0440\u043e\u043c, \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u0435\u043c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u0435 \u043d\u0430 AWS Lambda. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Snowflake, \u043d\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u043e\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Redshift. \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u0438 (\u043f\u043e \u043b\u043e\u0433\u0430\u043c) \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0439 \u0447\u0435\u043c \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 Google Cloud Function -> Google BigQuery. \u041d\u043e \u0443 \u043d\u0430\u0441 \u0435\u0449\u0435 \u043f\u043e\u0431\u043e\u0447\u043d\u0430\u044f \u0446\u0435\u043b\u044c \u2013 \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b, \u0447\u0442\u043e\u0431\u044b \u043a\u0430\u0436\u0434\u044b\u0439 \u043c\u043e\u0433 \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442.<\/p>\n<p>\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u0432 <a href=\"https:\/\/aws.amazon.com\/ru\/lambda\/\" rel=\"noopener noreferrer nofollow\"><u>AWS Lambda<\/u><\/a>. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>powerbi<\/strong> . \u0412\u0430\u0440\u0438\u0430\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u2013 \u201cStart with a simple Hello World example\u201d. <strong>Runtime<\/strong> \u2013 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0435\u0440\u0441\u0438\u044e Python, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0443 \u0432\u0430\u0441 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Python 3.8. \u0414\u0430\u043b\u0435\u0435 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0440\u0438\u0433\u0433\u0435\u0440 \u0442\u0438\u043f\u0430 <strong>API Gateway<\/strong> &#8212; <strong>HTTP API<\/strong>. Security \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c <strong>Open<\/strong>. \u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438, \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/933\/f13\/9e8\/933f139e8f4b6e4262610de0a43763f7.png\" width=\"996\" height=\"749\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/933\/f13\/9e8\/933f139e8f4b6e4262610de0a43763f7.png\"\/><figcaption><\/figcaption><\/figure>\n<p>URL \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u0438\u0434: <code>https:\/\/your-id.execute-api.us-east-2.amazonaws.com\/default\/powerbi?report=MyReport&amp;page=Page1<\/code><\/p>\n<p>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e Timeout \u0434\u043b\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 (\u0432\u0440\u0435\u043c\u044f \u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u044b) \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 3 \u0441\u0435\u043a\u0443\u043d\u0434\u044b. \u0414\u043b\u044f \u043d\u0430\u0441 \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u0442.\u043a. \u0431\u0443\u0434\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 Snowflake. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0443\u0436\u043d\u043e, \u0435\u0441\u043b\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c \u0440\u0435\u0434\u043a\u043e, \u0442.\u043a. \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0437\u0430\u043f\u0443\u0441\u043a Warehouse \u0432 Snowflake \u043f\u043e\u0441\u043b\u0435 \u0435\u0433\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438. \u0417\u0430\u0445\u043e\u0434\u0438\u043c \u0432 <strong>Configuration<\/strong> -> <strong>General configuration<\/strong> -> <strong>Edit<\/strong> -> <strong>Timeout = 12 sec<\/strong>.<\/p>\n<p><strong>6)<\/strong> Python \u043a\u043e\u0434 \u043d\u0430\u0448\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <strong>requests<\/strong> \u0438 <strong>snowflake.connector<\/strong>. \u0412 AWS Lambda \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u043d\u0435 \u0442\u0430\u043a \u043a\u0430\u043a \u0432 Google Cloud Functions. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435, \u043f\u043e\u0442\u043e\u043c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043c \u0432 Lambda zip-\u0430\u0440\u0445\u0438\u0432. <a href=\"https:\/\/docs.aws.amazon.com\/lambda\/latest\/dg\/python-package.html\" rel=\"noopener noreferrer nofollow\"><u>\u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f<\/u><\/a>. \u041f\u043e \u043c\u043e\u0435\u043c\u0443 \u043e\u043f\u044b\u0442\u0443, \u0441\u0430\u043c\u044b\u043c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442 <strong>Using a virtual environment<\/strong>.<\/p>\n<p>\u041d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0443\u0441\u0442\u0443\u044e \u043f\u0430\u043f\u043a\u0443, \u0433\u0434\u0435 \u0431\u0443\u0434\u0443\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430.\u00a0<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <strong>config.py<\/strong> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:\u00a0<\/p>\n<pre><code># id \u0447\u0430\u0442\u0430 \u0432 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u0435 \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0438. \u0447\u0442\u043e\u0431\u044b \u0443\u0437\u043d\u0430\u0442\u044c \u0441\u0432\u043e\u0439 id - \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0431\u043e\u0442\u0443 @userinfobot  tg_chat_id = 'XXXXXXX'  # \u0442\u043e\u043a\u0435\u043d \u0431\u043e\u0442\u0430. \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0431\u043e\u0442\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0432 @BotFather tg_bot_token = 'YYYYYYY:YYYYYYYYYYYYYYYYYYYYYYYYYY'   # \u043d\u0438\u0436\u0435 \u0440\u0435\u043a\u0432\u0438\u0437\u0438\u0442\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043e\u0442 snowflake. \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0437\u0430\u0440\u0430\u043d\u0435\u0435 sn_user = 'user_name' sn_password = 'user_password' sn_account = 'youproject.us-east-2.aws' sn_database = 'test' sn_schema = 'PUBLIC' sn_table = 'powerbi_views' sn_warehouse = 'COMPUTE_WH' sn_role_name = 'ACCOUNTADMIN'<\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <strong>lambda_function.py<\/strong> :<\/p>\n<pre><code>import datetime import json import requests import snowflake.connector from config import tg_chat_id, tg_bot_token, sn_user, sn_password, sn_account, \\                    sn_warehouse, sn_database, sn_table, sn_schema   def lambda_handler(event={}, context='', report='', page='', ip='', user_agent=''):     if event.get('queryStringParameters') is not None:         if 'report' in event['queryStringParameters']:             report = event['queryStringParameters']['report']         if 'page' in event['queryStringParameters']:             page = event['queryStringParameters']['page']         ip = event['headers']['x-forwarded-for']         user_agent = event['requestContext']['http']['userAgent']         time = datetime.datetime.utcnow()         return stream_snowflake(report, page, ip, time, user_agent)     else:         url = 'https:\/\/api.telegram.org\/bot' + tg_bot_token + '\/sendMessage?chat_id=' + tg_chat_id + '&amp;text=aws lambda powerbi error: event without parameters received. event = ' + str(event)         response = requests.get(url)         return 'event without parameters received'     def stream_snowflake(report, page, ip, time, user_agent):     error = False     try:         conn = snowflake.connector.connect(user=sn_user, password=sn_password, account=sn_account, warehouse=sn_warehouse,                                            database=sn_database, schema=sn_schema)         cs = conn.cursor()         cs.execute(             \"INSERT INTO \" + sn_table + \"(report, page, ip, time, user_agent) VALUES \" +             \"    (%s, %s, %s, %s, %s) \", (report, page, ip, time, user_agent))     except Exception as e:         error = True         url = 'https:\/\/api.telegram.org\/bot' + tg_bot_token + '\/sendMessage?chat_id=' + tg_chat_id + '&amp;text=aws lambda powerbi error:' + str(e)         response = requests.get(url)     finally:         try:             cs.close()         except Exception as u:             pass     if error == False:         return 'Write in snowflake successfully'     else:         return 'Was error with Snowflake. Send message to telegram'   # \u044d\u0442\u043e \u043a\u043e\u0434 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435 # if __name__== \"__main__\": #     lambda_handler()<\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435, \u0447\u0442\u043e \u043d\u0430\u0448 \u0441\u043a\u0440\u0438\u043f\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0440\u0430\u0441\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u043b\u043e\u043a \u0441\u043d\u0438\u0437\u0443 \u0438 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <strong>lambda_handler <\/strong>\u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0432\u044b\u0437\u043e\u0432 <strong>stream_snowflake<\/strong> \u0431\u0435\u0437 \u0443\u0441\u043b\u043e\u0432\u0438\u0439 (\u0442\u043e \u0435\u0441\u0442\u044c \u0441 \u043f\u0443\u0441\u0442\u044b\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 <strong>report<\/strong> \u0438 \u0442.\u0434.) \u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u043d\u043e\u0440\u043c, \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 AWS Lambda \u043f\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0443\u043d\u043a\u0442\u0430.<\/p>\n<p>\u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 URL \u0438\u0437 \u043f\u0443\u043d\u043a\u0442\u0430 5 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Lambda \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0447\u0442\u043e \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u041b\u043e\u0433\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 <strong>Monitor<\/strong> -> <strong>Logs<\/strong>.<\/p>\n<p><strong>7)<\/strong> \u0412 Snowflake \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u044b \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d54\/28b\/a1c\/d5428ba1c10133a301bbfa8cb2f52bee.png\" width=\"954\" height=\"64\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d54\/28b\/a1c\/d5428ba1c10133a301bbfa8cb2f52bee.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043e\u0431\u043e\u0433\u0430\u0442\u0438\u043c \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435:<\/p>\n<p><strong>7.1)<\/strong> \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u043e\u0431\u0449\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e geo-ip \u0432 Snowflake \u043d\u0435\u0442 (\u0438\u043b\u0438 \u044f \u043d\u0435 \u043d\u0430\u0448\u0435\u043b). \u041d\u043e \u043d\u0430 Snowflake Data Marketplace \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c 2-\u0445 \u043d\u0435\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0440\u0438\u0430\u043b \u043a <a href=\"https:\/\/www.snowflake.com\/datasets\/ipinfo-ip-geolocation\/\" rel=\"noopener noreferrer nofollow\"><u>IPINFO: IP GEOLOCATION<\/u><\/a> . \u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u0435\u0431\u0435. \u041f\u043e\u0441\u043b\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0442\u0440\u0438\u0430\u043b\u0430 \u043e\u043d\u0438 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u0443\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f. \u041d\u0430 \u043c\u043e\u044e \u043f\u0435\u0440\u0432\u0443\u044e \u0437\u0430\u044f\u0432\u043a\u0443 \u043d\u0435 \u0431\u044b\u043b\u043e \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0440\u0435\u0430\u043a\u0446\u0438\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0442\u043e\u0440\u043e\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u2013 \u0441 \u043d\u0438\u043c \u0432\u0441\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430, \u0435\u0441\u043b\u0438 \u043c\u044b \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <strong>CLONE<\/strong> &#8212; \u043d\u043e \u0442\u0430\u043c \u043f\u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0430: <em>SQL compilation error: Cannot clone from a table that was imported from a share.<\/em>   <\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0434\u0432\u0443\u043c\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438:<\/p>\n<pre><code>CREATE TABLE test.public.location_ip LIKE ipinfo_snowflake_myproject_trial.public.location; INSERT INTO test.public.location_ip SELECT * FROM ipinfo_snowflake_myproject_trial.public.location;<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0440\u0435\u0433\u0438\u043e\u043d\u0430 \u0438 \u0438\u043d\u0434\u0435\u043a\u0441\u0430 (\u043d\u0435 \u0432\u043b\u0435\u0437 \u043d\u0430 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442) \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 SQL-\u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<pre><code>SELECT *  FROM  (     SELECT ip,  PARSE_IP(ip, 'inet'):ipv4 AS ipv4      FROM ( SELECT ip FROM test.public.powerbi_views WHERE ip='X.X.X.X' GROUP BY ip )  ) AS q  LEFT JOIN test.public.location_ip AS l ON q.ipv4&lt;=l.end_ip_int AND q.ipv4>=l.start_ip_int<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f27\/a2c\/438\/f27a2c43888692974f68f95d6f994f7a.png\" width=\"802\" height=\"61\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f27\/a2c\/438\/f27a2c43888692974f68f95d6f994f7a.png\"\/><figcaption><\/figcaption><\/figure>\n<p><strong>7.2)<\/strong> \u0414\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 <strong>user_agent<\/strong> \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c JavaScript UDF \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0442.\u043a. \u0432 Snowflake \u043e\u043d\u0438 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f. \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 Java UDF \u0444\u0443\u043d\u043a\u0446\u0438\u0439 <a href=\"https:\/\/docs.snowflake.com\/en\/release-notes\/preview-features.html\" rel=\"noopener noreferrer nofollow\"><u>\u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u0430 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u043d\u0430 AWS<\/u><\/a>. \u0411\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/yauaa.basjes.nl\/udf\/snowflake\/\" rel=\"noopener noreferrer nofollow\"><u>Yauaa<\/u><\/a>.\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0432 \u0411\u0414 <strong>TEST<\/strong> \u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c Stage. \u041d\u0430\u0437\u043e\u0432\u0435\u043c \u0435\u0433\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <strong>YAUAA<\/strong>:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8b2\/9bc\/1ac\/8b29bc1ac725e71ddefad514c301add7.png\" width=\"1144\" height=\"478\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8b2\/9bc\/1ac\/8b29bc1ac725e71ddefad514c301add7.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0432\u044b\u0431\u0440\u0430\u043b\u0438 <strong>Snowflake Managed<\/strong>, \u0442\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0444\u0430\u0439\u043b \u0442\u0443\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/docs.snowflake.com\/en\/user-guide\/snowsql.html\" rel=\"noopener noreferrer nofollow\"><u>SnowSQL (CLI Client)<\/u><\/a> . \u041d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: \u0432 \u0444\u0430\u0439\u043b\u0435 .\/snowflake\/config <strong>region<\/strong> \u043d\u0443\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0432\u0435\u043d\u0434\u043e\u0440\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <strong>us-east-2.aws. <\/strong>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0443\u0442\u0438\u043b\u0438\u0442\u044b \u0444\u0430\u0439\u043b \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <strong>PUT<\/strong>: <code>put file:\/\/\/home\/anton\/yauaa-snowflake-6.9-udf.jar @YAUAA;<\/code><\/p>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439: <code>LIST @YAUAA;<\/code>\u00a0<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c UDF \u0444\u0443\u043d\u043a\u0446\u0438\u044e. \u0411\u0443\u0434\u044c\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u044b, \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u0430 <strong>imports <\/strong>\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u043e\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u0430:  <\/p>\n<pre><code>use test;  create or replace function parse_useragent(useragent VARCHAR) returns object language java imports = ('@YAUAA\/yauaa-snowflake-6.9-udf.jar') handler = 'nl.basjes.parse.useragent.snowflake.ParseUserAgent.parse';<\/code><\/pre>\n<p>SQL-\u043a\u043e\u0434 \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430:<\/p>\n<pre><code>SELECT    parse_useragent(user_agent):AgentName::string AS browser,    parse_useragent(user_agent):OperatingSystemName::string AS os,    user_agent FROM ( SELECT user_agent FROM test.public.powerbi_views GROUP BY user_agent )<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/19b\/36f\/cc0\/19b36fcc02066780cd3701d2a39b16ed.png\" width=\"595\" height=\"91\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/19b\/36f\/cc0\/19b36fcc02066780cd3701d2a39b16ed.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u0432 Snowflake \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u043a\u0430\u043a \u0432 BigQuery \u0432 \u043f\u0443\u043d\u043a\u0442\u0430\u0445 3 &#8212; 4. \u0412\u044b\u0431\u043e\u0440 \u0437\u0430 \u0432\u0430\u043c\u0438.\u00a0\u0421\u0447\u0435\u0442\u0447\u0438\u043a \u043c\u043e\u0436\u043d\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 PowerBI, \u043d\u043e \u0438 \u0432 \u0434\u0440\u0443\u0433\u0438\u0435 BI \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0430 \u0441\u0430\u0439\u0442, \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/654449\/\"> https:\/\/habr.com\/ru\/post\/654449\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u0441\u0447\u0435\u0442\u0447\u0438\u043a\u0438 \u0432\u0435\u0431 \u0438\u043b\u0438 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Google Analytics \u0438\u043b\u0438 AppsFlyer? \u041d\u0430 \u0441\u0430\u0439\u0442 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0438\u0445 \u043a\u043e\u0434\u044b \u0438\u043b\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 SDK. \u041f\u043e\u0442\u043e\u043c \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f http \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f Google Analytics \u0432 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442: <code>https:\/\/analytics.google.com\/g\/collect?v=2&amp;tid=G-XXXXXXXXXX&amp;cid=1415663337.1642776362&amp;en=order<\/code> , \u0433\u0434\u0435:<\/p>\n<ul>\n<li>\n<p><strong>tid<\/strong> &#8212; \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043f\u043e\u0442\u043e\u043a\u0430(\u0441\u0447\u0435\u0442\u0447\u0438\u043a\u0430)<\/p>\n<\/li>\n<li>\n<p><strong>cid<\/strong> &#8212; \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430<\/p>\n<\/li>\n<li>\n<p><strong>en<\/strong> &#8212; \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/p>\n<\/li>\n<\/ul>\n<p>\u0423 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u0441\u0447\u0435\u0442\u0447\u0438\u043a\u043e\u0432\/\u043f\u0438\u043a\u0441\u0435\u043b\u0435\u0439 \u0435\u0441\u0442\u044c \u043c\u0438\u043d\u0443\u0441\u044b:<\/p>\n<ul>\n<li>\n<p>\u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0441\u0435\u0442\u0438\u0442\u0435\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0430\u043d\u043e\u043d\u0438\u043c\u0430\u0439\u0437\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442 \u0442\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b;  <\/p>\n<\/li>\n<li>\n<p>\u0438\u0445 \u0441\u043b\u043e\u0436\u043d\u043e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0441\u0435\u0431\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u0447\u0435\u0442\u0447\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0448\u0430\u0442\u044c \u044d\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u0421\u0447\u0435\u0442\u0447\u0438\u043a \u0432\u0441\u0442\u0440\u043e\u0438\u043c \u0432 PowerBI \u043e\u0442\u0447\u0435\u0442\u044b. \u041d\u043e \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432, \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u043d\u0430 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u0435, \u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0438 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445\u00a0 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0443. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0434\u0432\u0435 \u0442\u043e\u0447\u043a\u0438 \u0441\u0431\u043e\u0440\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439: Google Cloud Function, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432 Google BigQuery, \u0438 Amazon Lambda Functions \u0441 \u0437\u0430\u043f\u0438\u0441\u044c\u044e \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Snowflake.<\/p>\n<p><strong>1) <\/strong>\u00a0\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 <a href=\"https:\/\/console.cloud.google.com\/functions\/add\" rel=\"noopener noreferrer nofollow\"><u>Google Cloud Function &#8212; Create function<\/u><\/a>. \u0423\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0442\u0440\u0438\u0433\u0433\u0435\u0440 <strong>HTTP<\/strong>, \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0433\u0430\u043b\u043e\u0447\u043a\u0430 \u043d\u0430\u043f\u0440\u043e\u0442\u0438\u0432 <strong>Require authentication<\/strong>. \u0416\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0447\u0442\u043e\u0431\u044b <strong>Region<\/strong> \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u043b \u0441 \u0440\u0435\u0433\u0438\u043e\u043d\u043e\u043c \u0432 \u0432\u0430\u0448\u0435\u043c \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0435 \u0432 BigQuery.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p><strong>URL<\/strong> \u043d\u0430 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u0435 \u2013 \u044d\u0442\u043e \u0442\u043e\u0442 \u0430\u0434\u0440\u0435\u0441, \u043a\u0443\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f.\u00a0\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>https:\/\/us-central1-project-name.cloudfunctions.net\/powerbi<\/code>\u00a0<\/p>\n<p>\u0427\u0435\u0440\u0435\u0437 GET \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043d\u0430 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c referrer. \u0412 \u043d\u0430\u0448\u0435\u043c \u0436\u0435 \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u0447\u0435\u0442\u0430 \u0432 PowerBI \u0438 \u0438\u043c\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. \u0422\u043e\u0433\u0434\u0430 \u0430\u0434\u0440\u0435\u0441 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u0438\u0434: <code>https:\/\/us-central1-project-name.cloudfunctions.net\/powerbi?report=MyReport&amp;page=Page1<\/code>  <\/p>\n<p><strong>2)<\/strong> \u0414\u0430\u043b\u0435\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c Python. \u0412 \u0444\u0430\u0439\u043b\u0435 <strong>requirements.txt<\/strong> \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442:  <\/p>\n<pre><code>requests>=2.27.1 google.cloud>=0.34.0 google-cloud-bigquery>=2.32.0<\/code><\/pre>\n<p>\u0412 \u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <strong>config.py<\/strong> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:\u00a0<\/p>\n<pre><code># id \u0447\u0430\u0442\u0430 \u0432 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u0435 \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0438. \u0447\u0442\u043e\u0431\u044b \u0443\u0437\u043d\u0430\u0442\u044c \u0441\u0432\u043e\u0439 id - \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0431\u043e\u0442\u0443 @userinfobot  tg_chat_id = 'XXXXXXX'  # \u0442\u043e\u043a\u0435\u043d \u0431\u043e\u0442\u0430. \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0431\u043e\u0442\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0432 @BotFather tg_bot_token = 'YYYYYYY:YYYYYYYYYYYYYYYYYYYYYYYYYY'  # \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 BigQuery \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \u0415\u0435 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0437\u0430\u0440\u0430\u043d\u0435\u0435. bq_table_name = 'project-name.dataset.powerbi_views'<\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b <strong>main.py<\/strong>:\u00a0<\/p>\n<pre><code>import datetime import requests from google.cloud import bigquery from config import tg_chat_id, tg_bot_token, bq_table_name   def main(request, report='', page='', ip='', user_agent=''):     if 'report' in request.args:         report = request.args['report']     if 'page' in request.args:         page = request.args['page']        #for headers in request.headers:  header = header + str(headers)  # \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438     ip = request.headers['X-Forwarded-For']     user_agent = request.headers['User-Agent']       if report != '':         return stream_bq(report, page, ip, user_agent)     else:         url = 'https:\/\/api.telegram.org\/bot' + tg_bot_token + '\/sendMessage?chat_id=' + tg_chat_id + '&amp;text=google cloud functions powerbi error: event without parameters received'         response = requests.get(url)         return 'event without parameters received'        def stream_bq(report, page, ip, user_agent):     bq_client = bigquery.Client()     bq_table = bq_client.get_table(bq_table_name)     row = [{'report': report,             'page': page,             'ip': ip,             'timestamp': datetime.datetime.utcnow(),             'user_agent': user_agent  }]     bq_client.insert_rows(bq_table, row)     return 'ok'<\/code><\/pre>\n<p>\u041d\u0430\u0436\u0438\u043c\u0430\u0435\u043c <strong>Deploy<\/strong>, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443: \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 <strong>URL<\/strong> \u0438\u0437 \u043f\u0443\u043d\u043a\u0442\u0430 1. \u0414\u043e\u043b\u0436\u043d\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u201c\u043e\u043a\u201d. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u2013 \u0438\u0449\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 <strong>Logs.<\/strong>  <\/p>\n<p><strong>3)<\/strong> \u0412 BigQuery \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c  \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043e\u0431\u043e\u0433\u0430\u0442\u0438\u043c \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435:<\/p>\n<p><strong>3.1)<\/strong> \u041f\u043e <strong>ip<\/strong>\u00a0 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0441\u0442\u0440\u0430\u043d\u0443, \u0433\u043e\u0440\u043e\u0434, \u043f\u043e\u0447\u0442\u043e\u0432\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0434\u0430\u043d\u043d\u044b\u0435 <a href=\"https:\/\/cloud.google.com\/blog\/products\/data-analytics\/geolocation-with-bigquery-de-identify-76-million-ip-addresses-in-20-seconds\" rel=\"noopener noreferrer nofollow\"><u>GeoLite2 Free Geolocation Data<\/u><\/a>:  <\/p>\n<pre><code>SELECT *  FROM ( SELECT ip FROM `project-name.dataset.powerbi_views` GROUP BY ip ) AS q  CROSS JOIN (    SELECT country_name, network, network_bin, city_name, postal_code, mask    FROM `fh-bigquery.geocode.201806_geolite2_city_ipv4_locs`  ) AS g  WHERE network_bin = NET.IP_FROM_STRING(ip) &amp; NET.IP_NET_MASK(4, mask)<\/code><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p><strong>3.2)<\/strong> \u0418\u0437 <strong>user_agent<\/strong> \u0432\u044b\u0434\u0435\u043b\u0438\u043c\u00a0 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f JS \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/github.com\/woothee\/woothee-js\/tree\/master\/release\" rel=\"noopener noreferrer nofollow\"><u>woothee<\/u><\/a>:<\/p>\n<pre><code>CREATE OR REPLACE FUNCTION `project-name.dataset.decode_user_agent`(ua STRING)    RETURNS STRING    LANGUAGE js AS \"\"\"  return JSON.stringify(woothee.parse(ua));    \"\"\"OPTIONS(library=\"gs:\/\/project-name-bucket\/woothee.js\");<\/code><\/pre>\n<pre><code>SELECT JSON_VALUE(json, '$.os') AS os, JSON_VALUE(json, '$.name') AS browser, json, user_agent, FROM  (    SELECT user_agent, `bproject-name.dataset.decode_user_agent`(user_agent) AS json    FROM `bi-analytics-318415.Others.powerbi_views`    GROUP BY user_agent )<\/code><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:  <\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p><strong>3.3)<\/strong> \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0437\u043d\u0430\u0435\u043c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043c\u043e\u0442\u0440\u044f\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438, \u043d\u043e \u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443. \u041c\u043e\u0436\u043d\u043e \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0447\u0435\u0442\u043d\u043e\u0441\u0442\u044c \u043d\u0430 \u0441\u0432\u043e\u0439 \u0432\u043a\u0443\u0441.<\/p>\n<p><strong>4)<\/strong> \u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448 \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0432 PowerBI. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u2013 \u043d\u0430\u0448\u0438\u043c URL:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0417\u0430\u0442\u0435\u043c \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u044d\u0442\u0443 \u043a\u043e\u043b\u043e\u043d\u043a\u0443 \u0441\u043f\u0440\u0430\u0432\u0430 \u0438 \u0432 \u043c\u0435\u043d\u044e <strong>Column tools<\/strong> \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c <strong>Data category<\/strong> = <strong>Image URL<\/strong>:<\/p>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043e\u0442\u0447\u0435\u0442 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u201c\u0442\u0430\u0431\u043b\u0438\u0446\u0430\u201d \u0441 \u044d\u0442\u043e\u0439 \u043a\u043e\u043b\u043e\u043d\u043a\u043e\u0439 \u0433\u0434\u0435-\u043d\u0438\u0431\u0443\u0434\u044c \u0432 \u043c\u0430\u043b\u043e\u0437\u0430\u043c\u0435\u0442\u043d\u043e\u043c \u0443\u0433\u043b\u0443 \u043e\u0442\u0447\u0435\u0442\u0430. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0435\u0433\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u0443\u0445\u043e\u0434\u0438\u0442\u044c http \u0437\u0430\u043f\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0447\u0435\u0440\u0435\u0437 Cloud Functions \u0431\u0443\u0434\u0435\u0442 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 BigQuery. <strong>\u041d\u0430\u0448 \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0433\u043e\u0442\u043e\u0432!<\/strong><\/p>\n<p><strong>5) <\/strong>\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u044b\u0442\u044c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u043c \u043e\u0434\u043d\u0438\u043c \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u043c \u0432\u0435\u043d\u0434\u043e\u0440\u043e\u043c, \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u0435\u043c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u0435 \u043d\u0430 AWS Lambda. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Snowflake, \u043d\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u043e\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Redshift. \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u0438 (\u043f\u043e \u043b\u043e\u0433\u0430\u043c) \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0439 \u0447\u0435\u043c \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 Google Cloud Function -> Google BigQuery. \u041d\u043e \u0443 \u043d\u0430\u0441 \u0435\u0449\u0435 \u043f\u043e\u0431\u043e\u0447\u043d\u0430\u044f \u0446\u0435\u043b\u044c \u2013 \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b, \u0447\u0442\u043e\u0431\u044b \u043a\u0430\u0436\u0434\u044b\u0439 \u043c\u043e\u0433 \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442.<\/p>\n<p>\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u0432 <a href=\"https:\/\/aws.amazon.com\/ru\/lambda\/\" rel=\"noopener noreferrer nofollow\"><u>AWS Lambda<\/u><\/a>. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>powerbi<\/strong> . \u0412\u0430\u0440\u0438\u0430\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u2013 \u201cStart with a simple Hello World example\u201d. <strong>Runtime<\/strong> \u2013 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0435\u0440\u0441\u0438\u044e Python, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0443 \u0432\u0430\u0441 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Python 3.8. \u0414\u0430\u043b\u0435\u0435 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0440\u0438\u0433\u0433\u0435\u0440 \u0442\u0438\u043f\u0430 <strong>API Gateway<\/strong> &#8212; <strong>HTTP API<\/strong>. Security \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c <strong>Open<\/strong>. \u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438, \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>URL \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u0438\u0434: <code>https:\/\/your-id.execute-api.us-east-2.amazonaws.com\/default\/powerbi?report=MyReport&amp;page=Page1<\/code><\/p>\n<p>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e Timeout \u0434\u043b\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 (\u0432\u0440\u0435\u043c\u044f \u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u044b) \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 3 \u0441\u0435\u043a\u0443\u043d\u0434\u044b. \u0414\u043b\u044f \u043d\u0430\u0441 \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u0442.\u043a. \u0431\u0443\u0434\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 Snowflake. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0443\u0436\u043d\u043e, \u0435\u0441\u043b\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c \u0440\u0435\u0434\u043a\u043e, \u0442.\u043a. \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0437\u0430\u043f\u0443\u0441\u043a Warehouse \u0432 Snowflake \u043f\u043e\u0441\u043b\u0435 \u0435\u0433\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438. \u0417\u0430\u0445\u043e\u0434\u0438\u043c \u0432 <strong>Configuration<\/strong> -> <strong>General configuration<\/strong> -> <strong>Edit<\/strong> -> <strong>Timeout = 12 sec<\/strong>.<\/p>\n<p><strong>6)<\/strong> Python \u043a\u043e\u0434 \u043d\u0430\u0448\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <strong>requests<\/strong> \u0438 <strong>snowflake.connector<\/strong>. \u0412 AWS Lambda \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u043d\u0435 \u0442\u0430\u043a \u043a\u0430\u043a \u0432 Google Cloud Functions. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435, \u043f\u043e\u0442\u043e\u043c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043c \u0432 Lambda zip-\u0430\u0440\u0445\u0438\u0432. <a href=\"https:\/\/docs.aws.amazon.com\/lambda\/latest\/dg\/python-package.html\" rel=\"noopener noreferrer nofollow\"><u>\u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f<\/u><\/a>. \u041f\u043e \u043c\u043e\u0435\u043c\u0443 \u043e\u043f\u044b\u0442\u0443, \u0441\u0430\u043c\u044b\u043c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442 <strong>Using a virtual environment<\/strong>.<\/p>\n<p>\u041d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0443\u0441\u0442\u0443\u044e \u043f\u0430\u043f\u043a\u0443, \u0433\u0434\u0435 \u0431\u0443\u0434\u0443\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430.\u00a0<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <strong>config.py<\/strong> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:\u00a0<\/p>\n<pre><code># id \u0447\u0430\u0442\u0430 \u0432 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u0435 \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0438. \u0447\u0442\u043e\u0431\u044b \u0443\u0437\u043d\u0430\u0442\u044c \u0441\u0432\u043e\u0439 id - \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0431\u043e\u0442\u0443 @userinfobot  tg_chat_id = 'XXXXXXX'  # \u0442\u043e\u043a\u0435\u043d \u0431\u043e\u0442\u0430. \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0431\u043e\u0442\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0432 @BotFather tg_bot_token = 'YYYYYYY:YYYYYYYYYYYYYYYYYYYYYYYYYY'   # \u043d\u0438\u0436\u0435 \u0440\u0435\u043a\u0432\u0438\u0437\u0438\u0442\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043e\u0442 snowflake. \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0437\u0430\u0440\u0430\u043d\u0435\u0435 sn_user = 'user_name' sn_password = 'user_password' sn_account = 'youproject.us-east-2.aws' sn_database = 'test' sn_schema = 'PUBLIC' sn_table = 'powerbi_views' sn_warehouse = 'COMPUTE_WH' sn_role_name = 'ACCOUNTADMIN'<\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <strong>lambda_function.py<\/strong> :<\/p>\n<pre><code>import datetime import json import requests import snowflake.connector from config import tg_chat_id, tg_bot_token, sn_user, sn_password, sn_account, \\                    sn_warehouse, sn_database, sn_table, sn_schema   def lambda_handler(event={}, context='', report='', page='', ip='', user_agent=''):     if event.get('queryStringParameters') is not None:         if 'report' in event['queryStringParameters']:             report = event['queryStringParameters']['report']         if 'page' in event['queryStringParameters']:             page = event['queryStringParameters']['page']         ip = event['headers']['x-forwarded-for']         user_agent = event['requestContext']['http']['userAgent']         time = datetime.datetime.utcnow()         return stream_snowflake(report, page, ip, time, user_agent)     else:         url = 'https:\/\/api.telegram.org\/bot' + tg_bot_token + '\/sendMessage?chat_id=' + tg_chat_id + '&amp;text=aws lambda powerbi error: event without parameters received. event = ' + str(event)         response = requests.get(url)         return 'event without parameters received'     def stream_snowflake(report, page, ip, time, user_agent):     error = False     try:         conn = snowflake.connector.connect(user=sn_user, password=sn_password, account=sn_account, warehouse=sn_warehouse,                                            database=sn_database, schema=sn_schema)         cs = conn.cursor()         cs.execute(             \"INSERT INTO \" + sn_table + \"(report, page, ip, time, user_agent) VALUES \" +             \"    (%s, %s, %s, %s, %s) \", (report, page, ip, time, user_agent))     except Exception as e:         error = True         url = 'https:\/\/api.telegram.org\/bot' + tg_bot_token + '\/sendMessage?chat_id=' + tg_chat_id + '&amp;text=aws lambda powerbi error:' + str(e)         response = requests.get(url)     finally:         try:             cs.close()         except Exception as u:             pass    <\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-330359","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/330359","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=330359"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/330359\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=330359"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=330359"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=330359"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}