BigQuery-ის მონაცემთა ბაზების ანალიტიკა Jupyter Notebook -ით
By: Tedo Gogoladze
Tags: Jupyter Notebook, Stackoverflow, Cloud Services, Python, Bigquery

4: BigQuery-ის გარემო, მონაცემების დამუშავების რესურსები და ლიმიტი.

საჯარო მონაცემების დამატების შემდეგ შესაძლებელია მათი პირდაპირ BigQuery-ს გარემოში დამუშავებაც SQL ბრძანებების გაშვებით.

არ გამოგრჩეთ BigQuery სანდბოქსის ლიმიტი: მაქსიმუმ 1 ტერაბაიტი მონაცემების დამუშავებაა ნებადართული ერთ თვეში. თუ ეს ლიმიტი ამოიწურება, ბრძანებები აღარ გაეშვება. თითოეულ SQL ბრძანებას გარკვეული რაოდენობის რესურსს ამუშავებს და ჯამურად ეს ბრძანებები 1 ტერაბაიტზე ნაკლები უნდა იყოს ერთი კალენდარული თვის განმავლობაში.

BigQuery -ს შეუძლია ყოველ ბრძანებაზე გამოითვალოს საჭირო რესურსი და აჩვენოს მომხმარებელს, სანამ ამ ბრძანების გაშვება მოხდება. მაგალითისთვის, როგორც ქვემოთა სურათზეა, სტაკოვერფლოუს მომხმარებლების მთლიანი ცხრილის ჩვენების ბრძანება საკმაოდ ძვირი სიამოვნებაა - 2.2 გბ.

LIMIT ფუნქციით შედეგების რაოდენობის შემცირება დასამუშავებელი რესურსის რაოდენობას არ შეცვლის, რადგან ბიგქუერი ჯერ მთლიანი ცხრილის სკანირებას ახდენს, რასაც უკვე დიდი რესურსი მიაქვს, და მხოლოდ ამის შემდეგ მიემართება LIMIT ფუნქცია, რომელიც უკვე გამოთვლილი შედეგებიდან (რომელზეც რესურსი უკვე დაიხარჯა) ნაწილს გვიჩვენებს. უფრო ეფექტიანი ბრძანებებისთვის უმჯობესია ფილტრების გამოყენება partition (დანაყოფ?) ველებზე, აგრეგაცია, ველების მხოლოდ ნაწილის — საჭირო ველების გამოტანა ყველაფრის (*) ნაცვლად და ა.შ. უფრო ვრცლად ამ საკითხზე: https://cloud.google.com/bigquery/docs/best-practices-costs

5. Google BigQuery-თვის საჭირო ბიბლიოთეკების ინსტალაცია და ჩატვირთვა Jupyter Notebook-ში.

ზემოთ მოცემული ეტაპების გავლის შემდეგ ბიგქუერი მზადაა გარე აპლიკაციებში გამოსაყენებლად, თუმცა პითონთან სამუშაოდ საჭიროა პითონის რამდენიმე ბიბლიოთეკის ინსტალაცია, ესენია: google-cloud-bigquery, google-cloud-bigquery-storage, pandas, pyarrow, seaborn(ეს ვიზუალიზაციისთვის). ამ ბიბლიოთეკების დაყენება შესაძლებელია როგორც ტრადიციული მეთოდით — ბრძანებების მმართველით (Terminal /Command Line: pip install), ასევე პირდაპირ Jupyter Notebook-იდანაც inline ბრძანებით:

!conda install -c conda-forge google-cloud-bigquery \

google-cloud-bigquery-storage \

pandas \

pyarrow --y



!pip install seaborn --y

6: Jupyter Notebook-იდან BigQuery-ზე დაკავშირება და მონაცემების წამოღება.

ამ ეტაპისთვის დაგვჭირდება ბიგქუერის სერვისის ანგარიშის გასაღების JSON ფაილი, რომელით ზემოთ (ეტაპი 2-ის ბოლოს) დავაგენერირეთ, ჩემ შემთხვევაში ესაა ფაილი bigquery-sandbox.json (მოათავსეთ ფაილი იმავე საქაღალდეში სადაც თქვენი სამუშაო Jupyter Notebook სკრიპტია. თუ JSON ფაილი ამ ფოლდერში არაა, მაშინ მიუთითეთ ფაილის სრული მისამართი). ქვემოთ მოცემული ბრძანებით ხდება ბიგქუერის კლიენტთან დაკავშირება. გასატესტად, შეგვიძლია გავუშვათ ბრძანება, რომელიც სტაკოვერფლოუს მონაცემთა ბაზაში მომხმარებლების რაოდენობას აჩვენებს და შედეგი pandas dataframe ფორმატში შევინახოთ:

import os

os.environ['GOOGLE_APPLICATION_CREDENTIALS'] ='bigquery-sandbox.json'



import pandas as pd

from google.cloud import bigquery

from google.cloud import bigquery_storage



bigquery_client = bigquery.Client()

bqstorageclient = bigquery_storage.BigQueryReadClient()



myQuery = """

SELECT count(*) AS total_count_of_users

FROM `bigquery-public-data.stackoverflow.users`

"""



job = bigquery_client.query(myQuery)

df = job.to_dataframe(bqstorage_client=bqstorageclient)

df.head()

ზედმეტი რესურსის ხარჯვის თავიდან ასაცილებლად, შესაძლებელია dry run ფუნქციის გამოყენება, რომელიც ბრძანების რეალურად გაშვების გარეშე აჩვენებს რა მოცულობის რესურსია საჭირო ამ ბრძანების გასაშვებად, ე.ი. მუშაობს ზუსტად ისე როგორც BigQuery-ს გარემოში იყო ბრძანების რესურსის გამომთვლელი. ამისთვის საჭიროა dry run კონფიგურაციის პარამეტრის დამატება ბიგქუერის ბრძანების გაშვებამდე:

config_dry_run = bigquery.QueryJobConfig(dry_run=True, use_query_cache=False)

და შემდეგ ბიგქუერის ბრძანების გაშვებისას საჭიროა ამ პარამეტრის მითითება:

config_dry_run = bigquery.QueryJobConfig(dry_run=True, use_query_cache=False)



print("The first query will consume {} MegaBytes.".format(

bigquery_client.query("SELECT count(*) AS total_count_of_users FROM `bigquery-public-data.stackoverflow.users` ", config_dry_run)

.total_bytes_processed/(1024*1024)))



print("The second query will consume {} MegaBytes.".format(

bigquery_client.query("SELECT * FROM `bigquery-public-data.stackoverflow.users`", config_dry_run)

.total_bytes_processed/(1024*1024)))

BigQuery-ს SQL კოდის გაშვება ასევე შესაძლებელია ე.წ. მაგიური ბრძანებებით (magic commands). ამისთვის ჯერ საჭიროა ზოგადად ამ ფუნქციონალის ჩატვირთვა %load_ext google.cloud.bigquery ბრძანებით და შემდეგ უკვე ახალ ველში %%bigquery მითითება და SQL კოდის ჩვეულებრივად ჩაწერა (კოდი მუშაობს იმ დაშვებით, რომ ნოუთბუქი უკვე დაკავშირებულია ბიგქუერის ბაზასთან). ქვემოთ მოცემულ სკრიპტს გამოაქვს მომხმარებლების მიერ დაფიქსირებული ქართული ლოკაციები, (თუმცა რისკი რომ Georgia ლოკაცია ამერიკელ ჯორჯიელებს აქვთ მითითებული მაინც გვრჩება):

%%bigquery

SELECT location, count(*) AS Count_of_users

FROM `bigquery-public-data.stackoverflow.users`

WHERE (

UPPER(location) LIKE '%TBILISI%'

OR UPPER(location) LIKE '%GEORGIA%'

OR location LIKE '%თბილისი%'

OR location LIKE '%საქართველო%'

)

AND NOT (

UPPER(location) LIKE '%USA%'

OR UPPER(location) LIKE '%STATES%'

OR UPPER(location) LIKE '%ATLANTA%'

)

GROUP BY location

ORDER BY count(*) DESC

LIMIT 5;

7: მონაცემების საბაზისო დამუშავება, ანალიზი და ვიზუალიზაცია.

ზემოთ ნაჩვენები სკრიპტების გამოყენებით უკვე შესაძლებელია Stackoverflow-ს მომხმარებელთა მონაცემების წამოღება დასამუშავებლად.

ქვემოთ მოცემული სნიპეტით პითონი უკავშირდება და აკოპირებს რეპუტაციის მიხედვით ტოპ 30 ქართველი მომხმარებლის შეკითხვებს. (1.6 გბ-ს ამუშავებს ბიგქუერი, თუმცა გადმოსაწერი მოცულობა გაცილებით ნაკლებია, 5 წუთამდე შეიძლება დაჭირდეს გადმოსაწერად) და ინახავს pandas dataframe-შ.

გამარტივებული ანალიზისთვის შევამციროთ იუზერების რაოდენობა და stackoverflow-ის რეპუტაციის მიხედვით ტოპ 30 ქართველი მომხმარებლის პოსტებზე ვიმუშაოთ. შეკითხვებისა და მომხმარებლების ცხრილების დაკავშირებახდება მომხმარებლის იდენტიფიკატორით, რომელიც მომხმარებლების ცხრილში ინახება როგორც id ხოლო შეკითხვების ცხრილში - owner_user_id

Query = """

WITH GEO_LOCATIONS AS (

SELECT location, count(*) AS Count_of_users

FROM `bigquery-public-data.stackoverflow.users`

WHERE (

UPPER(location) LIKE '%TBILISI%' OR UPPER(location) LIKE '%GEORGIA%'

OR location LIKE '%თბილისი%' OR location LIKE '%საქართველო%'

)

AND NOT

(UPPER(location) LIKE '%USA%' OR UPPER(location) LIKE '%STATES%'OR UPPER(location) LIKE '%ATLANTA%')

GROUP BY location

ORDER BY count(*) DESC

LIMIT 5)



SELECT P.id, P.tags, P.view_count, P.score, P.owner_user_id, U.display_name, U.location

FROM `bigquery-public-data.stackoverflow.posts_questions` AS P

INNER JOIN (

SELECT id, display_name, location

FROM `bigquery-public-data.stackoverflow.users` AS U

WHERE U.location IN (SELECT location FROM GEO_LOCATIONS)

ORDER BY reputation DESC

LIMIT 30) AS U ON P.owner_user_id = U.id

;

"""

print("The second query will consume {} MegaBytes.".format(

bigquery_client.query(Query, config_dry_run)

.total_bytes_processed/(1024*1024)))

ბიგქუერის მიერ დაბრუნებული შედეგების შენახვა პირდაპირ pandas dataframe-ში:

users_job = bigquery_client.query(Query)

user_posts = users_job.to_dataframe(bqstorage_client=bqstorageclient).copy()

user_posts.head(3)

ამ მომხმარებლების შეკითხვებზე მიღებული ქულების (“upvote”) ვიზუალიზაციისთვის ბოქსპლოტი ერთ-ერთი საუკეთესო ვარიანტია:

მომხმარებელთა შეკითხვებზე ქულების (“upvote”-ების) განაწილება: უმჯობესია ე.წ. აუთლაიერების (ამ შემთხვევაში score 100+) აქედანვე მოცილება რომ უფრო წაკითხვადი იყოს გრაფიკი

import seaborn as sns



user_posts_merged_no_outliers = user_posts[user_posts['score']<100].copy()

hm=sns.set(rc={'figure.figsize':(15, 8)})

g = sns.boxplot(x = user_posts_merged_no_outliers['display_name'], y = user_posts_merged_no_outliers['score'])

g = g.set_xticklabels(g.get_xticklabels(), rotation=40)

აქვე შეგვიძლია სკატერპლოტზე შევამოწმოთ x-ღერძზე შეკითხვებზე ქულების(ანუ “upvote”-ების) და y-ღერძზე ამ შეკითხვების ნახვების რაოდნობის დამოკიდებულება.

hm=sns.set(rc={'figure.figsize':(10, 6)}) plt.scatter(x = user_posts_merged_no_outliers['score'], y = user_posts_merged_no_outliers['view_count'])

თეგების ველი როგორც წესი რამდენიმე მნიშვნელობას შეიცავს, რომლებიც “|” სიმბოლოთია გამოყოფილი. თეგების უკეთესი ანალიზისთვის უმჯობესია თუ თითოეულ ამ თეგს ცალკე სტრიქონის მნიშვნელობად გამოვყოფთ. ასევე, ფილტრი score>0 გამორიცხავს უხარისხო შეკითხვებს. ანალიზის შედეგები ასეთია:

user_posts_filtered = user_posts[user_posts['score']>0].copy()

user_posts_filtered_row_level_tags = user_posts_filtered.assign(

tag=user_posts_filtered['tags'].str.split('|')).explode('tag')

print('top 30 ქართველი მომხმარებლის დასმული შეკითხვების საერთო რაოდენობა: ', user_posts.shape[0],

'

მათ შორის შეკითხვები დადებითი ქულით (upvote 0+): ', user_posts_filtered.shape[0]

, '

ასეთ შეკითხვებში ერთეული თაგების(tag) რაოდენობა: ', user_posts_filtered_row_level_tags.shape[0])

დაჯგუფება თეგის მიხედვით და აგრეგატები: შეკითხვების რაოდენობა ამ თეგზე(id), საშუალო აფვოუთები თეგზე(score), საშუალო ნახვების რაოდენობა თეგზე (view_count). ადამიანური ვიზუალიზაციისთვის წამოვიღოთ ტოპ 30 თეგები რაოდენობის მიხედვით:

plot_data = user_posts_filtered_row_level_tags.groupby('tag').agg(

{'id': 'count', 'score': 'mean', 'view_count': 'mean'}).sort_values(

'id', ascending=False).head(30).reset_index()

შედეგის გამოტანა პლოტზე:

import matplotlib.pyplot as plt



g=sns.set(rc={'figure.figsize':(16, 6)})

g = sns.barplot(x = plot_data['tag'], y = plot_data['id'])

g = sns.lineplot(x = plot_data['tag'], y=plot_data['score'], color = "black", legend="full")

g = sns.lineplot(x = plot_data['tag'], y=plot_data['view_count']/1000, color = "purple")

g = g.set_xticklabels(g.get_xticklabels(), rotation=90)

როგორც ჩანს, ყველაზე მეტი შეკითხვა C#, C++, javascript და php -ზეა დასმული. თუმცა ამ შეკითხვებს საშუალოდ საკმაოდ მცირე ნახვები და ქულები აქვს. ნახვებისა და აფვოუთების კომპონენტში css, html და database თეგები ლიდერობენ. პ.ს. გრაფიკზე საშუალო ნახვების შესადარისობისთვის ეს მაჩვენებლი გაყოფილია 1000-ზე.

შეკითხვების რაოდენობა შეგვიძლია ასევე გამოვიტანოთ თეგისა და მომხმარებელის კომბინაციის ჭრილში ჰითმაპის საშუალებით. უკეთესი ვიზუალიზაციისთვის უმჯოებსია აქაც იგივე ფილტრი გამოვიყენოთ, რომელიც მხოლოდ 20 ყველაზე ხშირ თეგს წამოიღებს.

import seaborn as sns



plot_data2 = user_posts_filtered_row_level_tags[

user_posts_filtered_row_level_tags['tag'].isin(plot_data['tag'])]

tab = pd.crosstab(plot_data2['tag']

, plot_data2['display_name']

, values = plot_data2['id']

, aggfunc = 'count')



hm=sns.set(rc={'figure.figsize':(12, 6)})

hm = sns.heatmap(tab, annot=False, cmap="Greens")

Jupyter Notebook-ის სრული კოდი ატვირთულია გითჰაბზე:

ზემოთ მოყვანილი მაგალითი მხოლოდ ილუსტრაციაა თუ როგორ შეიძლება პითონით ბიგქუერის მონაცემების დამუშავება. ეს შეიძლება პირველი ეტაპი იყოს დამწყები მონაცემთა ანალიტიკოსის/ინჟინერის ქლაუდ სერვისებში უკეთ გასარკვევად. რეალობაში BigQuery-სა და მსგავს სერვისებს (Snowflake, Redshift, etc.) გამოყენება “ენთერფრაის” მონაცემთა საწყობებისთვისაა რეკომენდირებული და სავარაუდოდ არც თუ ისე ბევრი კომპანია იყენებს საქართველოში, შესაბამისად დამწყებებისთვის ამ ტექნოლოგიების შესასწავლად სანდბოქსი და საცდელი პერიოდი (free trial) ძალიან კარგი საშუალებაა.