Hi all, I've simple code. All I'm trying to do is ...
# troubleshooting
j
Hi all, I've simple code. All I'm trying to do is group the data. However it is not grouping the data when I print. dt = datetime.fromtimestamp(epoch_time) # print(dt) table = t_env.from_elements([(1, 10, 'ml' ,dt), (2, 20, 'ml', dt), (3, 25, 'policy', dt)], DataTypes.ROW([DataTypes.FIELD("a", DataTypes.INT()), DataTypes.FIELD("b", DataTypes.INT()), DataTypes.FIELD("c", DataTypes.STRING()), DataTypes.FIELD("rowtime", DataTypes.TIMESTAMP(3)), ])) # # table.print_schema() table.execute().print() # # # orders = t_env.from_path("table") # # table.window(Tumble.over(lit(2).seconds).on(col('rowtime')).alias("w"))\ result = table\ .group_by(col("c"))\ .select(col("c"), col("b").count.alias('d')) result.execute().print() +----+-------------+-------------+--------------------------------+-------------------------+ | op | a | b | c | rowtime | +----+-------------+-------------+--------------------------------+-------------------------+ | +I | 1 | 10 | ml | 2023-02-19 181416.000 | | +I | 2 | 20 | ml | 2023-02-19 181416.000 | | +I | 3 | 25 | policy | 2023-02-19 181416.000 | +----+-------------+-------------+--------------------------------+-------------------------+ 3 rows in set +----+--------------------------------+----------------------+ | op | c | d | +----+--------------------------------+----------------------+ | +I | policy | 1 | | +I | ml | 1 | | -U | ml | 1 | | +U | ml | 2 | +----+--------------------------------+----------------------+ 4 rows in set
also I've other issue with same code. When I'm am using tumble to group by 1 min. it throws any error. result = table\ .window(Tumble.over(lit(1).minutes).on(col('rowtime')).alias("w"))\ .group_by(col("w"),col("c"))\ .select(col("w"),col("c"), col("b").count.alias('d')) result.execute().print()
: org.apache.flink.table.api.ValidationException: A group window expects a time attribute for grouping in a stream environment. at org.apache.flink.table.operations.utils.AggregateOperationFactory.validateStreamTimeAttribute(AggregateOperationFactory.java:327) at org.apache.flink.table.operations.utils.AggregateOperationFactory.validateTimeAttributeType(AggregateOperationFactory.java:307) at org.apache.flink.table.operations.utils.AggregateOperationFactory.getValidatedTimeAttribute(AggregateOperationFactory.java:300) at org.apache.flink.table.operations.utils.AggregateOperationFactory.createResolvedWindow(AggregateOperationFactory.java:265) at org.apache.flink.table.operations.utils.OperationTreeBuilder.windowAggregate(OperationTreeBuilder.java:262) at org.apache.flink.table.api.internal.TableImpl$WindowGroupedTableImpl.select(TableImpl.java:640) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.apache.flink.api.python.shaded.py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:244) at org.apache.flink.api.python.shaded.py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357) at org.apache.flink.api.python.shaded.py4j.Gateway.invoke(Gateway.java:282) at org.apache.flink.api.python.shaded.py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132) at org.apache.flink.api.python.shaded.py4j.commands.CallCommand.execute(CallCommand.java:79) at org.apache.flink.api.python.shaded.py4j.GatewayConnection.run(GatewayConnection.java:238) at java.base/java.lang.Thread.run(Thread.java:834)
d
Re grouping issue: Actually it has grouped the data. You are running the job in streaming mode where it processed the data row by row. The meaning of
op
column: •
+I
: insert a new row •
-U
: Remove the old row •
+U
: Insert a new row From the output you have posted, it means that for group
ml
, the count is firstly
1
and then becomes
2
.
🙌 1
You could also run it in batch mode and then you will only see the final result.
🙌 1
Re the exception: You are running the job in streaming mode and row time column(not just Timestamp type) must be part of the grouping key. Could refer to https://github.com/apache/flink/blob/master/flink-python/pyflink/examples/table/windowing/tumble_window.py as an example.
j
thank you @Dian Fu for looking into my issue. I got clarity on what you are referring.
However, coming back to Tumble Window example. I'm using row time column (which is timestamp) as part of grouping key if you see my example.
Why I'm using this way because, let me give background of what I'm trying to achieve.
In my current project, we are trying to connect kafka using table api kafka connector and sink with another kafka topic.
we want to achieve this using table environment created using streaming mode
for example the code looks like this
from pyflink.table import EnvironmentSettings, TableEnvironment # create a stream TableEnvironment env_settings = EnvironmentSettings.in_streaming_mode() table_env = TableEnvironment.create(env_settings) table_env.execute_sql(""" CREATE TABLE random_source (
@timestamp
BIGINT, ts as TO_TIMESTAMP(FROM_UNIXTIME(
@timestamp
)), id BIGINT, data TINYINT ) WITH ( 'connector' = 'kafka', 'topic' = 'user_behavior_source', 'properties.bootstrap.servers' = 'localhost:9092', 'properties.group.id' = 'testGroup', 'scan.startup.mode' = 'earliest-offset', 'format' = 'json' ) """) table = table_env.from_path("random_source") table_env.execute_sql(""" CREATE TABLE sink_table ( one_minute_window timestamp, id BIGINT, data_count TINYINT ) WITH ( 'connector' = 'upsert-kafka', 'topic' = 'user_behavior_sink', 'properties.bootstrap.servers' = 'localhost:9092', 'properties.group.id' = 'testGroup', 'format' = 'json' ) """) sink_table = table_env.from_path("sink_table") #table.execute().print() result = table\ .window(Tumble.over(lit(1).minutes).on(col('ts')).alias("one_minute_window"))\ .group_by(col("one_minute_window"),col("id"))\ .select(col("one_minute_window"),col("id"), col("data").count.alias('data_count')) # develop code to sink with another kafka topic result.execute().print() # for now print the results and see. #result1 = result.execute_insert("sink_table")
The code works perfectly. But only the problem it sinks old records also op=-U
d
@Jagan Nalla Only declaring a column as Timestamp type isn’t enough. You should also define how watermark is generated from that column which actually turns it into a row time column. See the following examples: • Define watermark in DDL: https://nightlies.apache.org/flink/flink-docs-release-1.16/docs/dev/table/sql/create/#watermark • Define watermark in API way: https://github.com/apache/flink/blob/master/flink-python/pyflink/examples/table/windowing/tumble_window.py#L55
The code works perfectly. But only the problem it sinks old records also op=-U
Yes, this is by design as -U message is also part of the changelog. Maybe you could try upsert-kafka: https://nightlies.apache.org/flink/flink-docs-release-1.16/docs/connectors/table/upsert-kafka/
j
Thanks @Dian Fu, much appreciated for your education.
I'm new to Apache Flink and trying to understand and implementing the solutions on fly. It looks like I'm missing lot of basic stuff. But your information what you provided me is awesome. Let me go through it and understand.
🎉 1
Hi @Dian Fu I am very close. But not sure where I am making mistake. I am attaching sample code what I am using and trying to develop.
test.py
when I run I am getting this error.
: org.apache.flink.table.api.ValidationException: Cannot resolve field [one_minute_window], input field list:[type, EXPR$0].
I want to ask one more question which is not relevant to above thread issue. However if you can help me, that will be Awesome! Thanks and much appreciated.
test_case_1.py
In the above example, I've prepared one sample data and created table api.
for that table I want to write a group by logic using table api and generate the output as show in below format. Not sure what is the best idea to develop the code.
I want to group the data by "company" and remaining are measures.
Much appreciated if you can help me on this. Thanks a lot.
d
Re the exception: You can only select the start/end of the window, e.g.
col('one_minute_window').start or col('one_minute_window').end
, instead of
col('one_minute_window')
.
🙌 1
For your requirements, I have written a simple example:
Copy code
import json

import pandas as pd
from pyflink.common import Configuration

from pyflink.table import EnvironmentSettings, TableEnvironment, DataTypes

# create a batch TableEnvironment
from pyflink.table.expressions import col
from pyflink.table.udf import udaf

conf = Configuration()
env_settings = EnvironmentSettings.in_batch_mode()
table_env = TableEnvironment.create(env_settings)

table = table_env.from_elements(
    [(1, 'apple', 200, "a"),
     (2, 'samsung', 300, "s"),
     (3, 'nokia', 400, "n"),
     (1, 'apple', 300, "a1"),
     (2, 'samsung', 400, "s1"),
     (3, 'nokia', 500, "n1"),
     (1, 'apple', 100, "a2")
    ],
    ['id', 'company', 'price', 'category'])


@udaf(result_type=DataTypes.STRING(), func_type="pandas")
def metadata(price: pd.Series, category: pd.Series):
    result = {
        'count': price.size,
        'price': price.tolist(),
        'category': category.tolist()
    }
    return str(json.dumps(result))


@udaf(result_type=DataTypes.BIGINT(), func_type="pandas")
def total(price: pd.Series):
    return int(price.sum())


table = table.group_by(col('id'), col('company')) \
    .select(col('company'),
            total(col('price')).alias('total'),
            col('id'),
            metadata(col('price'), col('category')).alias('metadata'))

table.execute().print()

# with table.execute().collect() as results:
#     for result in results:
#         print(result)
🙌 1
🙌 1
It prints the above results. For the last column, the results are truncated. There is a JIRA to improve this which allows to configure the max display column width: https://issues.apache.org/jira/browse/FLINK-30025
j
Thank you @Dian Fu
Nice idea on the second question. I'll sure try it.
after adding col('five_seconds_window').start,col('five_seconds_window').end it doesn't throw error
so far good.
But it didn't prints the results when I tried to print it or sink to another topic
for example
I defined the kafka topic properties like this
In above screenshot if you see there are not results it is producing
However when I stop doing window group by and print the results of table directly. It shows the results of incoming records of kafka topic
Here is another screenshot of it
I'm very very close to achieve this solution all because of you, once I've this group results then my idea is to store the results in the format what you suggested to me for my second question ( metadata column with json format). I am not able to run the sample code in my local machine (windows) using python virtual environment set up. However I've a docker container with flink and python and I tried it and worked like a charm. Thank you. But when I changed the env setting to stream mode to the sample example what you provided me, like below code then it throws error. I'm enclosing the error too. Because down the line I want to use the json format conversion on incoming messages of kafka topic through window aggregation. env_settings = EnvironmentSettings.in_streaming_mode() table_env = TableEnvironment.create(env_settings) ------------------------- error ---- pyflink.util.exceptions.TableException: org.apache.flink.table.api.TableException: Cannot generate a valid execution plan for the given query: FlinkLogicalSink(table=[anonymous_collect$2], fields=[company, total, id, metadata]) +- FlinkLogicalCalc(select=[company, EXPR$0 AS total, id, EXPR$1 AS metadata]) +- FlinkLogicalAggregate(group=[{0, 1}], EXPR$0=[*org.apache.flink.table.functions.python.PythonAggregateFunction$2595d75109319bc0ebcb9b7a185a1be8*($2)], EXPR$1=[*org.apache.flink.table.functions.python.PythonAggregateFunction$c0b392a2af72b7d0801546c286cbee53*($2, $3)]) +- FlinkLogicalTableSourceScan(table=[[anonymous_python-input-format$1]], fields=[id, company, price, category]) Pandas UDAFs are not supported in streaming mode currently. Please check the documentation for the set of currently supported SQL features.
I'm also enclosing the error which I got when I'm running locally on windows through python. Toovercome the problem I reffered this solution and didn't work when I run set no_proxy=localhost https://stackoverflow.com/questions/68015759/whats-wrong-with-my-pyflink-setup-that-python-udfs-throw-py4j-exceptions
error_for_dev_json_format.txt
d
Re no results problem: I guess it may be related to this [1] (there is no data in some partitions of your kafka topic), you could set configuration
table.exec.source.idle-timeout
or set the parallelism to 1 to work around it during testing. [1] https://nightlies.apache.org/flink/flink-docs-release-1.16/docs/connectors/table/kafka/#source-per-partition-watermarks
❤️ 1
🎉 1
🙌 1
j
let me look and set it
d
Re
Pandas UDAFs are not supported in streaming mode currently.
: There are three types of aggregation: • GroupBy Aggregation: https://nightlies.apache.org/flink/flink-docs-release-1.16/docs/dev/table/tableapi/#groupby-aggregation • GroupBy Window Aggregation: https://nightlies.apache.org/flink/flink-docs-release-1.16/docs/dev/table/tableapi/#groupby-window-aggregation • Over Window Aggreagation: https://nightlies.apache.org/flink/flink-docs-release-1.16/docs/dev/table/tableapi/#over-window-aggregation Pandas UDF could only be used in the latter two in streaming mode:
GroupBy Window Aggregation
and
Over Window Aggreagation
. The reason is that the data is unbounded in streaming mode, for the first kind of aggregation
GroupBy Aggregation
, we could not collect all the data belonging to one group and so not able to construct pandas.Series for the input parameters of Pandas UDAF. For
GroupBy Window Aggregation
and
Over Window Aggreagation
, window could be used to separate the unbounded data into a series of bounded data batch and so Pandas UDAF could be used.
❤️ 1
🎉 1
🙌 1
j
after adding set the parallelism to 1 it is grouping the data using tumble window
👏 1
🎉 1
So Pandas can be used for GroupBy Window Aggregation.
Awesome!
d
Yes, you are right.
j
Awesome let me quickly try the example what you provided
currently I've results like this
It throws an error with no message
py4j.protocol.Py4JJavaError: An error occurred while calling o146.execute. : java.lang.NullPointerException at org.apache.flink.util.Preconditions.checkNotNull(Preconditions.java:59) at org.apache.flink.table.functions.python.PythonFunctionInfo.<init>(PythonFunctionInfo.java:45) at org.apache.flink.table.functions.python.PythonAggregateFunctionInfo.<init>(PythonAggregateFunctionInfo.java:36) at org.apache.flink.table.planner.plan.nodes.exec.utils.CommonPythonUtil.extractPythonAggregateFunctionInfosFromAggregateCall(CommonPythonUtil.java:262) at org.apache.flink.table.planner.plan.nodes.exec.stream.StreamExecPythonGroupWindowAggregate.createPandasPythonStreamWindowGroupOneInputTransformation(StreamExecPythonGroupWindowAggregate.java:406) at org.apache.flink.table.planner.plan.nodes.exec.stream.StreamExecPythonGroupWindowAggregate.translateToPlanInternal(StreamExecPythonGroupWindowAggregate.java:297) at org.apache.flink.table.planner.plan.nodes.exec.ExecNodeBase.translateToPlan(ExecNodeBase.java:158) at org.apache.flink.table.planner.plan.nodes.exec.ExecEdge.translateToPlan(ExecEdge.java:257) at org.apache.flink.table.planner.plan.nodes.exec.common.CommonExecCalc.translateToPlanInternal(CommonExecCalc.java:94) at org.apache.flink.table.planner.plan.nodes.exec.ExecNodeBase.translateToPlan(ExecNodeBase.java:158) at org.apache.flink.table.planner.plan.nodes.exec.ExecEdge.translateToPlan(ExecEdge.java:257) at org.apache.flink.table.planner.plan.nodes.exec.stream.StreamExecSink.translateToPlanInternal(StreamExecSink.java:145) at org.apache.flink.table.planner.plan.nodes.exec.ExecNodeBase.translateToPlan(ExecNodeBase.java:158) at org.apache.flink.table.planner.delegation.StreamPlanner.$anonfun$translateToPlan$1(StreamPlanner.scala:85) at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:233) at scala.collection.Iterator.foreach(Iterator.scala:937) at scala.collection.Iterator.foreach$(Iterator.scala:937) at scala.collection.AbstractIterator.foreach(Iterator.scala:1425) at scala.collection.IterableLike.foreach(IterableLike.scala:70) at scala.collection.IterableLike.foreach$(IterableLike.scala:69) at scala.collection.AbstractIterable.foreach(Iterable.scala:54) at scala.collection.TraversableLike.map(TraversableLike.scala:233) at scala.collection.TraversableLike.map$(TraversableLike.scala:226) at scala.collection.AbstractTraversable.map(Traversable.scala:104) at org.apache.flink.table.planner.delegation.StreamPlanner.translateToPlan(StreamPlanner.scala:84) at org.apache.flink.table.planner.delegation.PlannerBase.translate(PlannerBase.scala:197) at org.apache.flink.table.api.internal.TableEnvironmentImpl.translate(TableEnvironmentImpl.java:1733) at org.apache.flink.table.api.internal.TableEnvironmentImpl.executeQueryOperation(TableEnvironmentImpl.java:874) at org.apache.flink.table.api.internal.TableEnvironmentImpl.executeInternal(TableEnvironmentImpl.java:1382) at org.apache.flink.table.api.internal.TableImpl.execute(TableImpl.java:475) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.apache.flink.api.python.shaded.py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:244) at org.apache.flink.api.python.shaded.py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357) at org.apache.flink.api.python.shaded.py4j.Gateway.invoke(Gateway.java:282) at org.apache.flink.api.python.shaded.py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132) at org.apache.flink.api.python.shaded.py4j.commands.CallCommand.execute(CallCommand.java:79) at org.apache.flink.api.python.shaded.py4j.GatewayConnection.run(GatewayConnection.java:238) at java.base/java.lang.Thread.run(Thread.java:834)
d
Need also replace
col('flowid').count
with pandas UDAF.
🙌 1
🎉 1
❤️ 1
j
Awesome !
Finally I understood how the Apache Flink streaming and batch processing is working. It made me to read and understand lot of articles.
But at the same time when there is any error it is getting more default to trace it out. Because few errors are not well described or I am not up to level to understand at this point.
@Dian Fu last and final question to close of this thread. Metadata column doesn't show up fully. It is truncating the data due to size. Is there any way to show it fully while printing in the console.
d
But at the same time when there is any error it is getting more default to trace it out. Because few errors are not well described or I am not up to level to understand at this point.
Yes, this is something which should be improved. However, it may need to take a very long time as it’s not very easy because it’s quite different for batch and streaming underlying.
🙌 1
j
Awesome!
Thank you very very much for teaching me, much appreciated for you patience. Have a wonderful day.
d
It prints the above results. For the last column, the results are truncated. There is a JIRA to improve this which allows to configure the max display column width: https://issues.apache.org/jira/browse/FLINK-30025
This is because currently the maximum display column width is by default 30 and there is no way to change it. For testing, I guess you could collect the data to client and print it yourself:
Copy code
with table.execute().collect() as results:
    for result in results:
        print(result)
🙌 1
Since you are running a streaming job, I guess finally you want to output the data to an external storage. If that’s the case, it should not be a big problem here.
j
Yes that is correct, after data processing logic I am going to feed it into another kafka topic / db table.
d
This maximum display column width limitation comes from the behavior of
print
and will not be a problem if you send out data to other storage.
🙌 1
j
few jobs I'm going to write into kafka topic and few jobs into db table
d
OK. Then the
print
issue is only a display issue and won’t be a problem when you write data to Kafka / DB.