Skip to content

Commit 808cc92

Browse files
authored
Merge pull request ClickHouse#349 from wudidapaopao/add-daft
2 parents 8879ce8 + eb130cd commit 808cc92

File tree

9 files changed

+500
-1
lines changed

9 files changed

+500
-1
lines changed

daft-parquet/benchmark.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/bash
2+
3+
machine=${1:-"c6a.4xlarge"}
4+
case "$machine" in
5+
"c6a.4xlarge"|"c6a.metal")
6+
machine_name="$machine"
7+
;;
8+
*)
9+
echo "Invalid machine parameter. Allowed: c6a.4xlarge or c6a.metal"
10+
exit 1
11+
;;
12+
esac
13+
14+
# Install
15+
sudo apt-get update
16+
sudo apt-get install -y python3-pip
17+
pip install --break-system-packages pandas
18+
pip install --break-system-packages packaging
19+
pip install --break-system-packages daft==0.4.9
20+
21+
# Use for Daft (Parquet, partitioned)
22+
seq 0 99 | xargs -P100 -I{} bash -c 'wget --continue https://datasets.clickhouse.com/hits_compatible/athena_partitioned/hits_{}.parquet'
23+
24+
# Use for Daft (Parquet, single)
25+
wget --continue https://datasets.clickhouse.com/hits_compatible/athena/hits.parquet
26+
27+
# Run the queries
28+
for mode in partitioned single; do
29+
echo "Running $mode mode..."
30+
./run.sh $machine_name $mode 2>&1 | tee "daft_log_${mode}.txt"
31+
done

daft-parquet/queries.sql

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
SELECT COUNT(*) FROM hits;
2+
SELECT COUNT(*) FROM hits WHERE AdvEngineID <> 0;
3+
SELECT SUM(AdvEngineID), COUNT(*), AVG(ResolutionWidth) FROM hits;
4+
SELECT AVG(UserID) FROM hits;
5+
SELECT COUNT(DISTINCT UserID) FROM hits;
6+
SELECT COUNT(DISTINCT SearchPhrase) FROM hits;
7+
SELECT MIN(EventDate) as m1, MAX(EventDate) as m2 FROM hits;
8+
SELECT AdvEngineID, COUNT(*) FROM hits WHERE AdvEngineID <> 0 GROUP BY AdvEngineID ORDER BY COUNT(*) DESC;
9+
SELECT RegionID, COUNT(DISTINCT UserID) AS u FROM hits GROUP BY RegionID ORDER BY u DESC LIMIT 10;
10+
SELECT RegionID, SUM(AdvEngineID), COUNT(*) AS c, AVG(ResolutionWidth), COUNT(DISTINCT UserID) FROM hits GROUP BY RegionID ORDER BY c DESC LIMIT 10;
11+
SELECT MobilePhoneModel, COUNT(DISTINCT UserID) AS u FROM hits WHERE MobilePhoneModel <> '' GROUP BY MobilePhoneModel ORDER BY u DESC LIMIT 10;
12+
SELECT MobilePhone, MobilePhoneModel, COUNT(DISTINCT UserID) AS u FROM hits WHERE MobilePhoneModel <> '' GROUP BY MobilePhone, MobilePhoneModel ORDER BY u DESC LIMIT 10;
13+
SELECT SearchPhrase, COUNT(*) AS c FROM hits WHERE SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY c DESC LIMIT 10;
14+
SELECT SearchPhrase, COUNT(DISTINCT UserID) AS u FROM hits WHERE SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY u DESC LIMIT 10;
15+
SELECT SearchEngineID, SearchPhrase, COUNT(*) AS c FROM hits WHERE SearchPhrase <> '' GROUP BY SearchEngineID, SearchPhrase ORDER BY c DESC LIMIT 10;
16+
SELECT UserID, COUNT(*) FROM hits GROUP BY UserID ORDER BY COUNT(*) DESC LIMIT 10;
17+
SELECT UserID, SearchPhrase, COUNT(*) FROM hits GROUP BY UserID, SearchPhrase ORDER BY COUNT(*) DESC LIMIT 10;
18+
SELECT UserID, SearchPhrase, COUNT(*) FROM hits GROUP BY UserID, SearchPhrase LIMIT 10;
19+
SELECT UserID, extract(minute FROM EventTime) AS m, SearchPhrase, COUNT(*) FROM hits GROUP BY UserID, m, SearchPhrase ORDER BY COUNT(*) DESC LIMIT 10;
20+
SELECT UserID FROM hits WHERE UserID = 435090932899640449;
21+
SELECT COUNT(*) FROM hits WHERE URL LIKE '%google%';
22+
SELECT SearchPhrase, MIN(URL), COUNT(*) AS c FROM hits WHERE URL LIKE '%google%' AND SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY c DESC LIMIT 10;
23+
SELECT SearchPhrase, MIN(URL), MIN(Title), COUNT(*) AS c, COUNT(DISTINCT UserID) FROM hits WHERE Title LIKE '%Google%' AND URL NOT LIKE '%.google.%' AND SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY c DESC LIMIT 10;
24+
SELECT * FROM hits WHERE URL LIKE '%google%' ORDER BY EventTime LIMIT 10;
25+
SELECT SearchPhrase FROM hits WHERE SearchPhrase <> '' ORDER BY EventTime LIMIT 10;
26+
SELECT SearchPhrase FROM hits WHERE SearchPhrase <> '' ORDER BY SearchPhrase LIMIT 10;
27+
SELECT SearchPhrase FROM hits WHERE SearchPhrase <> '' ORDER BY EventTime, SearchPhrase LIMIT 10;
28+
SELECT CounterID, AVG(length(URL)) AS l, COUNT(*) AS c FROM hits WHERE URL <> '' GROUP BY CounterID HAVING COUNT(*) > 100000 ORDER BY l DESC LIMIT 25;
29+
SELECT REGEXP_REPLACE(Referer, '^https?://(?:www\.)?([^/]+)/.*$', '\1') AS k, AVG(length(Referer)) AS l, COUNT(*) AS c, MIN(Referer) as m FROM hits WHERE Referer <> '' GROUP BY k HAVING COUNT(*) > 100000 ORDER BY l DESC LIMIT 25;
30+
SELECT SUM(ResolutionWidth) AS s0, SUM(ResolutionWidth + 1) AS s1, SUM(ResolutionWidth + 2) AS s2, SUM(ResolutionWidth + 3) AS s3, SUM(ResolutionWidth + 4) AS s4, SUM(ResolutionWidth + 5) AS s5, SUM(ResolutionWidth + 6) AS s6, SUM(ResolutionWidth + 7) AS s7, SUM(ResolutionWidth + 8) AS s8, SUM(ResolutionWidth + 9) AS s9, SUM(ResolutionWidth + 10) AS s10, SUM(ResolutionWidth + 11) AS s11, SUM(ResolutionWidth + 12) AS s12, SUM(ResolutionWidth + 13) AS s13, SUM(ResolutionWidth + 14) AS s14, SUM(ResolutionWidth + 15) AS s15, SUM(ResolutionWidth + 16) AS s16, SUM(ResolutionWidth + 17) AS s17, SUM(ResolutionWidth + 18) AS s18, SUM(ResolutionWidth + 19) AS s19, SUM(ResolutionWidth + 20) AS s20, SUM(ResolutionWidth + 21) AS s21, SUM(ResolutionWidth + 22) AS s22, SUM(ResolutionWidth + 23) AS s23, SUM(ResolutionWidth + 24) AS s24, SUM(ResolutionWidth + 25) AS s25, SUM(ResolutionWidth + 26) AS s26, SUM(ResolutionWidth + 27) AS s27, SUM(ResolutionWidth + 28) AS s28, SUM(ResolutionWidth + 29) AS s29, SUM(ResolutionWidth + 30) AS s30, SUM(ResolutionWidth + 31) AS s31, SUM(ResolutionWidth + 32) AS s32, SUM(ResolutionWidth + 33) AS s33, SUM(ResolutionWidth + 34) AS s34, SUM(ResolutionWidth + 35) AS s35, SUM(ResolutionWidth + 36) AS s36, SUM(ResolutionWidth + 37) AS s37, SUM(ResolutionWidth + 38) AS s38, SUM(ResolutionWidth + 39) AS s39, SUM(ResolutionWidth + 40) AS s40, SUM(ResolutionWidth + 41) AS s41, SUM(ResolutionWidth + 42) AS s42, SUM(ResolutionWidth + 43) AS s43, SUM(ResolutionWidth + 44) AS s44, SUM(ResolutionWidth + 45) AS s45, SUM(ResolutionWidth + 46) AS s46, SUM(ResolutionWidth + 47) AS s47, SUM(ResolutionWidth + 48) AS s48, SUM(ResolutionWidth + 49) AS s49, SUM(ResolutionWidth + 50) AS s50, SUM(ResolutionWidth + 51) AS s51, SUM(ResolutionWidth + 52) AS s52, SUM(ResolutionWidth + 53) AS s53, SUM(ResolutionWidth + 54) AS s54, SUM(ResolutionWidth + 55) AS s55, SUM(ResolutionWidth + 56) AS s56, SUM(ResolutionWidth + 57) AS s57, SUM(ResolutionWidth + 58) AS s58, SUM(ResolutionWidth + 59) AS s59, SUM(ResolutionWidth + 60) AS s60, SUM(ResolutionWidth + 61) AS s61, SUM(ResolutionWidth + 62) AS s62, SUM(ResolutionWidth + 63) AS s63, SUM(ResolutionWidth + 64) AS s64, SUM(ResolutionWidth + 65) AS s65, SUM(ResolutionWidth + 66) AS s66, SUM(ResolutionWidth + 67) AS s67, SUM(ResolutionWidth + 68) AS s68, SUM(ResolutionWidth + 69) AS s69, SUM(ResolutionWidth + 70) AS s70, SUM(ResolutionWidth + 71) AS s71, SUM(ResolutionWidth + 72) AS s72, SUM(ResolutionWidth + 73) AS s73, SUM(ResolutionWidth + 74) AS s74, SUM(ResolutionWidth + 75) AS s75, SUM(ResolutionWidth + 76) AS s76, SUM(ResolutionWidth + 77) AS s77, SUM(ResolutionWidth + 78) AS s78, SUM(ResolutionWidth + 79) AS s79, SUM(ResolutionWidth + 80) AS s80, SUM(ResolutionWidth + 81) AS s81, SUM(ResolutionWidth + 82) AS s82, SUM(ResolutionWidth + 83) AS s83, SUM(ResolutionWidth + 84) AS s84, SUM(ResolutionWidth + 85) AS s85, SUM(ResolutionWidth + 86) AS s86, SUM(ResolutionWidth + 87) AS s87, SUM(ResolutionWidth + 88) AS s88, SUM(ResolutionWidth + 89) AS s89 FROM hits;
31+
SELECT SearchEngineID, ClientIP, COUNT(*) AS c, SUM(IsRefresh), AVG(ResolutionWidth) FROM hits WHERE SearchPhrase <> '' GROUP BY SearchEngineID, ClientIP ORDER BY c DESC LIMIT 10;
32+
SELECT WatchID, ClientIP, COUNT(*) AS c, SUM(IsRefresh), AVG(ResolutionWidth) FROM hits WHERE SearchPhrase <> '' GROUP BY WatchID, ClientIP ORDER BY c DESC LIMIT 10;
33+
SELECT WatchID, ClientIP, COUNT(*) AS c, SUM(IsRefresh), AVG(ResolutionWidth) FROM hits GROUP BY WatchID, ClientIP ORDER BY c DESC LIMIT 10;
34+
SELECT URL, COUNT(*) AS c FROM hits GROUP BY URL ORDER BY c DESC LIMIT 10;
35+
SELECT 1, URL, COUNT(*) AS c FROM hits GROUP BY 1, URL ORDER BY c DESC LIMIT 10;
36+
SELECT ClientIP, ClientIP - 1, ClientIP - 2, ClientIP - 3, COUNT(*) AS c FROM hits GROUP BY ClientIP, ClientIP - 1, ClientIP - 2, ClientIP - 3 ORDER BY c DESC LIMIT 10;
37+
SELECT URL, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND DontCountHits = 0 AND IsRefresh = 0 AND URL <> '' GROUP BY URL ORDER BY PageViews DESC LIMIT 10;
38+
SELECT Title, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND DontCountHits = 0 AND IsRefresh = 0 AND Title <> '' GROUP BY Title ORDER BY PageViews DESC LIMIT 10;
39+
SELECT URL, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 AND IsLink <> 0 AND IsDownload = 0 GROUP BY URL ORDER BY PageViews DESC LIMIT 1010;
40+
SELECT TraficSourceID, SearchEngineID, AdvEngineID, CASE WHEN (SearchEngineID = 0 AND AdvEngineID = 0) THEN Referer ELSE '' END AS Src, URL AS Dst, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 GROUP BY TraficSourceID, SearchEngineID, AdvEngineID, Src, Dst ORDER BY PageViews DESC LIMIT 1010;
41+
SELECT URLHash, EventDate, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 AND TraficSourceID IN (-1, 6) AND RefererHash = 3594120000172545465 GROUP BY URLHash, EventDate ORDER BY PageViews DESC LIMIT 110;
42+
SELECT WindowClientWidth, WindowClientHeight, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 AND DontCountHits = 0 AND URLHash = 2868770270353813622 GROUP BY WindowClientWidth, WindowClientHeight ORDER BY PageViews DESC LIMIT 10010;
43+
SELECT DATE_TRUNC('minute', EventTime) AS M, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-14' AND EventDate <= '2013-07-15' AND IsRefresh = 0 AND DontCountHits = 0 GROUP BY DATE_TRUNC('minute', EventTime) ORDER BY DATE_TRUNC('minute', EventTime) LIMIT 1010;

daft-parquet/query.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#!/usr/bin/env python3
2+
3+
import daft
4+
import os
5+
import sys
6+
import timeit
7+
import traceback
8+
import pandas as pd
9+
from daft import col, DataType, TimeUnit
10+
11+
hits = None
12+
current_dir = os.path.dirname(os.path.abspath(__file__))
13+
query_idx = int(sys.argv[1]) - 1
14+
is_single_mode = len(sys.argv) > 2 and sys.argv[2] == "single"
15+
parquet_path = os.path.join(
16+
current_dir,
17+
"hits.parquet" if is_single_mode else "hits_*.parquet"
18+
)
19+
20+
with open("queries.sql") as f:
21+
sql_list = [q.strip() for q in f.read().split(';') if q.strip()]
22+
23+
def daft_offset(df, start ,end):
24+
pandas_df = df.to_pandas()
25+
sliced_df = pandas_df.iloc[start:end]
26+
return sliced_df
27+
28+
queries = []
29+
for idx, sql in enumerate(sql_list):
30+
query_entry = {"sql": sql}
31+
32+
# Current limitations and workarounds for Daft execution:
33+
34+
# 1. Queries q18, q35, q42 require manual API workarounds:
35+
# - q18: The function `extract(minute FROM EventTime)` causes an error:
36+
# `expected input to minute to be temporal, got UInt32`.
37+
# - q35: Error is `duplicate field name ClientIP in the schema`.
38+
# Attempts to alias the column in SQL but still failed.
39+
# - q42: The function `DATE_TRUNC('minute', EventTime)` causes an error:
40+
# `Unsupported SQL: Function date_trunc not found`.
41+
if idx in [18, 35, 42]:
42+
if idx == 18:
43+
query_entry["lambda"] = lambda: (
44+
hits.with_column("m", col("EventTime").dt.minute())
45+
.groupby("UserID", "m", "SearchPhrase")
46+
.agg(daft.sql_expr("COUNT(1)").alias("COUNT(*)"))
47+
.sort("COUNT(*)", desc=True)
48+
.limit(10)
49+
.select("UserID", "m", "SearchPhrase", "COUNT(*)")
50+
)
51+
elif idx == 35:
52+
query_entry["lambda"] = lambda: (
53+
hits.groupby(
54+
"ClientIP",
55+
daft.sql_expr("ClientIP - 1").alias("ClientIP - 1"),
56+
daft.sql_expr("ClientIP - 2").alias("ClientIP - 2"),
57+
daft.sql_expr("ClientIP - 3").alias("ClientIP - 3"))
58+
.agg(daft.sql_expr("COUNT(1)").alias("c"))
59+
.sort("c", desc=True)
60+
.limit(10)
61+
.select("ClientIP", "ClientIP - 1", "ClientIP - 2", "ClientIP - 3", "c")
62+
)
63+
elif idx == 42:
64+
query_entry["lambda"] = lambda: (
65+
hits.with_column("M", col("EventTime").dt.truncate("1 minute"))
66+
.where("CounterID = 62 AND EventDate >= '2013-07-14' AND EventDate <= '2013-07-15' AND IsRefresh = 0 AND DontCountHits = 0")
67+
.groupby("M")
68+
.agg(daft.sql_expr("COUNT(1)").alias("PageViews"))
69+
.sort("M", desc=False)
70+
.limit(1010)
71+
.select("M", "PageViews")
72+
)
73+
74+
# 2. OFFSET operator not supported in Daft:
75+
# For queries q38, q39, q40, q41, q42, after executing the query,
76+
# manually implement the `OFFSET` truncation logic via the API
77+
if 38 <= idx <= 42:
78+
if idx == 38:
79+
query_entry["extra_api"] = lambda df: daft_offset(df, 1000, 1010)
80+
elif idx == 39:
81+
query_entry["extra_api"] = lambda df: daft_offset(df, 1000, 1010)
82+
elif idx == 40:
83+
query_entry["extra_api"] = lambda df: daft_offset(df, 100, 110)
84+
elif idx == 41:
85+
query_entry["extra_api"] = lambda df: daft_offset(df, 10000, 10010)
86+
elif idx == 42:
87+
query_entry["extra_api"] = lambda df: daft_offset(df, 1000, 1010)
88+
89+
queries.append(query_entry)
90+
91+
def run_single_query(query, i):
92+
try:
93+
start = timeit.default_timer()
94+
95+
global hits
96+
if hits is None:
97+
hits = daft.read_parquet(parquet_path)
98+
hits = hits.with_column("EventTime", col("EventTime").cast(daft.DataType.timestamp("s")))
99+
hits = hits.with_column("EventDate", col("EventDate").cast(daft.DataType.date()))
100+
hits = hits.with_column("URL", col("URL").decode("utf-8"))
101+
hits = hits.with_column("Title", col("Title").decode("utf-8"))
102+
hits = hits.with_column("Referer", col("Referer").decode("utf-8"))
103+
hits = hits.with_column("MobilePhoneModel", col("MobilePhoneModel").decode("utf-8"))
104+
hits = hits.with_column("SearchPhrase", col("SearchPhrase").decode("utf-8"))
105+
106+
result = None
107+
108+
if "lambda" in query:
109+
result = query["lambda"]()
110+
else:
111+
result = daft.sql(query["sql"])
112+
113+
result.collect()
114+
115+
if "extra_api" in query:
116+
result = query["extra_api"](result)
117+
118+
run_time = timeit.default_timer() - start
119+
120+
return run_time
121+
except Exception as e:
122+
print(f"Error executing query {query_idx}: {str(e)[:100]}", file=sys.stderr)
123+
traceback.print_exc()
124+
return None
125+
126+
if __name__ == "__main__":
127+
query = queries[query_idx]
128+
129+
times = []
130+
for i in range(3):
131+
elapsed = run_single_query(query, i)
132+
times.append(f"{elapsed}" if elapsed else "")
133+
134+
print(','.join(times))
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"system": "Daft (Parquet, partitioned)",
3+
"date": "2025-04-10",
4+
"machine": "c6a.4xlarge, 500gb gp2",
5+
"cluster_size": 1,
6+
"comment": "",
7+
"tags": [
8+
"Rust",
9+
"stateless",
10+
"serverless",
11+
"embedded"
12+
],
13+
"load_time": 0,
14+
"data_size": 14779976446,
15+
"result": [
16+
[2.9239969809987088,0.24281721499937703,0.25061354499848676],
17+
[2.943689669999003,0.24701748600091378,0.2412866730010137],
18+
[3.3013779040011286,0.3499440380001033,0.34748943700105883],
19+
[0.5240946279991476,0.14416759599953366,0.14079303099970275],
20+
[8.358806038000694,8.191848701000708,8.301089013999444],
21+
[7.3857230829999025,7.083538949000285,6.779509707001125],
22+
[0.44852974800051015,0.09936009000011836,0.09527912199882849],
23+
[2.9437991849990794,0.24986934899970947,0.249939440000162],
24+
[3.2667164159993263,2.9141958559994237,2.997278159000416],
25+
[6.341243853001288,2.2626934529998834,2.3228578489997744],
26+
[1.1101171179998346,0.8267360560002999,0.7852608660014084],
27+
[1.1224606880005012,0.8311700009999186,0.799573213000258],
28+
[5.719661522000024,2.2495632319987635,2.2330354629993963],
29+
[3.9945796060001157,2.910399188000156,2.8959377400005906],
30+
[5.794290511999861,2.249771316000988,2.2831605970004603],
31+
[6.017177588000777,2.6195074140014185,2.6053394909995404],
32+
[9.390984196999852,5.380491128000358,5.675109460000385],
33+
[7.000278958999843,2.909169999000369,2.9183442980011023],
34+
[10.517328523001197,9.270337152998763,9.211842022999917],
35+
[0.4838494970008469,0.13263488300071913,0.13043909699990763],
36+
[13.509324963999461,2.8007291499998246,2.7599115609991713],
37+
[15.182025014000828,3.0815161779992195,3.0070982840006764],
38+
[25.465576216000045,7.294880023000587,7.23245921400121],
39+
[55.77252582199981,14.482481478000409,14.470004283999515],
40+
[5.588168801001302,3.3266251870009,3.264028256000529],
41+
[11.422374611000123,11.096233861000655,11.42879000799985],
42+
[8.442051498999717,6.437731754000197,6.3204276689994],
43+
[13.50050955000006,4.382914202000393,4.389906216998497],
44+
[54.93292986199958,54.7095186509996,54.55201650199888],
45+
[1.810280910000074,1.694118317000175,1.718246561000342],
46+
[6.6975024990006204,1.7159326830005739,1.6963492020004196],
47+
[7.2224263429998246,2.2286510949998046,2.2376933390005433],
48+
[14.639526433000356,12.763357517000259,12.641049649000706],
49+
[20.836833830000614,12.953915013998994,13.191902100001244],
50+
[19.975888697999835,12.617277572000603,12.521102639999299],
51+
[2.9711594529999275,2.7580122080016736,2.77822500900038],
52+
[0.7095541710004909,0.3223742640002456,0.2954207420007151],
53+
[0.5843301879995124,0.15686079099941708,0.14083533799930592],
54+
[0.6433542939994368,0.16117779100022744,0.14962360200115654],
55+
[0.9204736569990928,0.4168329120002454,0.4444124349993217],
56+
[0.5595925659999921,0.10117537899895979,0.09999015900029917],
57+
[0.5403744819996064,0.09798703699925682,0.09515768100027344],
58+
[0.5390828099989449,0.08939602699865645,0.08288451900079963]
59+
]
60+
}

0 commit comments

Comments
 (0)