blob: 4219643b9a7c90fdae424fc6d71f4051509a98ab [file]
################################################################################
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################
from typing import Optional
from pyflink.common import Configuration
from pyflink.java_gateway import get_gateway
from pyflink.table import EnvironmentSettings, StreamTableEnvironment, TableEnvironment
from pyflink.table.statement_set import StatementSet
from pyflink.util.api_stability_decorators import PublicEvolving
from pyflink.util.java_utils import get_j_env_configuration
__all__ = [
"set_table_environment",
"get_table_environment",
"get_or_create_table_environment",
"create_statement_set",
]
_global_table_environment: Optional[TableEnvironment] = None
@PublicEvolving()
def create_statement_set() -> StatementSet:
"""
Create a statement set for submitting multiple DataFrame writes as one job.
Pass the set as ``statement_set`` to a DataFrame writer to stage the write without
executing it. Call :meth:`~pyflink.table.StatementSet.execute` to submit the staged
writes, or :meth:`~pyflink.table.StatementSet.explain` to inspect their execution plan.
The set and its DataFrames must belong to the same TableEnvironment.
:return: A statement set using the configured or newly created DataFrame environment.
Example::
>>> import pyflink.dataframe as pf
>>> events = pf.from_records([(1, "login")], schema=["id", "event"])
>>> statement_set = pf.create_statement_set()
>>> events.write_json("file:///tmp/events-json", statement_set=statement_set)
>>> events.write_generic("blackhole", options={}, statement_set=statement_set)
>>> result = statement_set.execute()
.. versionadded:: 2.4.0
"""
return get_or_create_table_environment().create_statement_set()
@PublicEvolving()
def set_table_environment(t_env: Optional[TableEnvironment]) -> None:
"""
Set the environment used by DataFrame operations.
The injected environment is treated as fully configured: values buffered in
:data:`config` are not applied to it. Injecting an environment while :data:`config`
holds buffered values is rejected, because those values would otherwise be silently
ignored. Passing ``None`` clears the environment and leaves the buffered values intact.
:param t_env: Environment to use, or ``None`` to clear it.
:raises TypeError: If ``t_env`` is neither a :class:`TableEnvironment` nor ``None``.
:raises RuntimeError: If ``t_env`` is not ``None`` and :data:`config` holds buffered
values.
Example::
>>> import pyflink.dataframe as pf
>>> pf.set_table_environment(None)
>>> pf.get_table_environment() is None
True
.. versionadded:: 2.4.0
"""
global _global_table_environment
if t_env is not None and not isinstance(t_env, TableEnvironment):
raise TypeError("t_env must be a TableEnvironment or None")
if t_env is not None:
from pyflink.dataframe.dataframe_config import config
if config._buffered:
raise RuntimeError(
"pf.config holds buffered values that only apply to an environment created by "
"get_or_create_table_environment(); they would be ignored by the injected "
"environment. Configure that environment through t_env.get_config() instead of "
"pf.config, or call get_or_create_table_environment() to have the buffered "
"values applied."
)
_global_table_environment = t_env
@PublicEvolving()
def get_table_environment() -> Optional[TableEnvironment]:
"""
Return the environment used by DataFrame operations, if one is configured.
:return: The configured environment, or ``None``.
Example::
>>> import pyflink.dataframe as pf
>>> pf.set_table_environment(None)
>>> pf.get_table_environment() is None
True
.. versionadded:: 2.4.0
"""
return _global_table_environment
@PublicEvolving()
def get_or_create_table_environment() -> TableEnvironment:
"""
Return the configured environment, creating one when necessary.
The environment is created from the values buffered in :data:`config`, so options that
can only be chosen at creation time, such as ``execution.runtime-mode``, take effect.
It is retained for subsequent DataFrame operations and calls to
:func:`get_table_environment`.
:return: The configured or newly created environment.
Example::
>>> import pyflink.dataframe as pf
>>> pf.set_table_environment(None)
>>> environment = pf.get_or_create_table_environment()
>>> pf.get_table_environment() is environment
True
.. versionadded:: 2.4.0
"""
global _global_table_environment
if _global_table_environment is None:
from pyflink.dataframe.dataframe_config import config
from pyflink.datastream import RuntimeExecutionMode, StreamExecutionEnvironment
configuration = config._to_configuration()
stream_environment = StreamExecutionEnvironment.get_execution_environment(configuration)
# The execution environment may merge deployment configuration (for example, from the
# CLI or config.yaml) while it is being created. EnvironmentSettings must use this
# effective configuration because some Table API options are consumed during creation.
j_environment_configuration = get_j_env_configuration(
stream_environment._j_stream_execution_environment
)
environment_configuration = Configuration(
j_configuration=j_environment_configuration
)
settings_builder = EnvironmentSettings.new_instance().with_configuration(
environment_configuration
)
# Match StreamTableEnvironment.create(executionEnvironment): Table API supports only an
# explicit batch or streaming mode, so AUTOMATIC is treated as streaming.
j_execution_options = (
get_gateway().jvm.org.apache.flink.configuration.ExecutionOptions
)
runtime_mode = RuntimeExecutionMode._from_j_execution_mode(
j_environment_configuration.get(j_execution_options.RUNTIME_MODE)
)
if runtime_mode == RuntimeExecutionMode.BATCH:
settings_builder.in_batch_mode()
else:
settings_builder.in_streaming_mode()
settings = settings_builder.build()
_global_table_environment = StreamTableEnvironment.create(
stream_environment, environment_settings=settings
)
return _global_table_environment