| # | |
| # 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 Set, List, Optional, cast | |
| from pywy.core.core import Plugin, PywyPlan | |
| from pywy.operators.base import PO_T | |
| from pywy.types import (GenericTco, Predicate, Function, BiFunction, FlatmapFunction, IterableOut, T, In, Out) | |
| from pywy.operators import * | |
| from pywy.basic.data.record import Record | |
| from pywy.basic.model.option import Option | |
| from pywy.basic.model.models import (Model, LogisticRegression, DecisionTreeRegression, LinearSVC) | |
| from pywy.configuration import Configuration | |
| class WayangContext: | |
| """ | |
| This is the entry point for users to work with Wayang. | |
| """ | |
| plugins: Set[Plugin] | |
| configuration: Configuration | |
| def __init__(self, configuration: Configuration = Configuration()): | |
| self.plugins = set() | |
| self.configuration = configuration | |
| """ | |
| add a :class:`Plugin` to the :class:`Context` | |
| """ | |
| def register(self, *plugins: Plugin): | |
| for p in plugins: | |
| self.plugins.update(p) | |
| return self | |
| """ | |
| remove a :class:`Plugin` from the :class:`Context` | |
| """ | |
| def unregister(self, *plugins: Plugin): | |
| for p in plugins: | |
| self.plugins.remove(p) | |
| return self | |
| def textfile(self, file_path: str) -> "DataQuanta[str]": | |
| return DataQuanta(self, TextFileSource(file_path)) | |
| def parquet( | |
| self, file_path: str, projection: Optional[List[str]] = None, column_names: Optional[List[str]] = None | |
| ) -> "DataQuanta[Record]": | |
| return DataQuanta(self, ParquetSource(file_path, projection, column_names)) | |
| def __str__(self): | |
| return "Plugins: {}".format(str(self.plugins)) | |
| def __repr__(self): | |
| return self.__str__() | |
| class DataQuanta(GenericTco): | |
| """ | |
| Represents an intermediate result/data flow edge in a [[WayangPlan]]. | |
| """ | |
| context: WayangContext | |
| def __init__(self, context: WayangContext, operator: PywyOperator): | |
| self.operator = operator | |
| self.context = context | |
| def filter(self: "DataQuanta[T]", p: Predicate, input_type: GenericTco = None) -> "DataQuanta[T]": | |
| return DataQuanta(self.context, self._connect(FilterOperator(p, input_type))) | |
| def map( | |
| self: "DataQuanta[In]", | |
| f: Function, | |
| input_type: GenericTco = None, | |
| output_type: GenericTco = None | |
| ) -> "DataQuanta[Out]": | |
| return DataQuanta(self.context, self._connect(MapOperator(f, input_type, output_type))) | |
| def flatmap( | |
| self: "DataQuanta[In]", | |
| f: FlatmapFunction, | |
| input_type: GenericTco = None, | |
| output_type: GenericTco = None | |
| ) -> "DataQuanta[IterableOut]": | |
| return DataQuanta(self.context, self._connect(FlatmapOperator(f, input_type, output_type))) | |
| def reduce_by_key( | |
| self: "DataQuanta[In]", | |
| key_f: Function, | |
| f: BiFunction, | |
| input_type: GenericTco = None | |
| ) -> "DataQuanta[IterableOut]": | |
| return DataQuanta(self.context, self._connect(ReduceByKeyOperator(key_f, f, input_type))) | |
| def sort(self: "DataQuanta[In]", key_f: Function, input_type: GenericTco = None) -> "DataQuanta[IterableOut]": | |
| return DataQuanta(self.context, self._connect(SortOperator(key_f, input_type))) | |
| def join( | |
| self: "DataQuanta[In]", | |
| this_key_f: Function, | |
| that: "DataQuanta[In]", | |
| that_key_f: Function, | |
| input_type: GenericTco = None, | |
| ) -> "DataQuanta[Out]": | |
| op = JoinOperator( | |
| this_key_f, | |
| that, | |
| that_key_f, | |
| input_type | |
| ) | |
| self._connect(op), | |
| return DataQuanta( | |
| self.context, | |
| that._connect(op, 1) | |
| ) | |
| def cartesian( | |
| self: "DataQuanta[In]", | |
| that: "DataQuanta[In]", | |
| input_type: GenericTco = None, | |
| ) -> "DataQuanta[Out]": | |
| op = CartesianOperator( | |
| that, | |
| input_type | |
| ) | |
| self._connect(op), | |
| return DataQuanta( | |
| self.context, | |
| that._connect(op, 1) | |
| ) | |
| def dlTraining( | |
| self: "DataQuanta[In]", | |
| model: Model, | |
| option: Option, | |
| that: "DataQuanta[In]", | |
| input_type: GenericTco, | |
| output_type: GenericTco | |
| ) -> "DataQuanta[Out]": | |
| op = DLTrainingOperator( | |
| model, | |
| option, | |
| input_type, | |
| output_type | |
| ) | |
| self._connect(op) | |
| return DataQuanta( | |
| self.context, | |
| that._connect(op, 1) | |
| ) | |
| def predict( | |
| self: "DataQuanta[In]", | |
| that: "DataQuanta[In]", | |
| input_type: GenericTco, | |
| output_type: GenericTco | |
| ) -> "DataQuanta[Out]": | |
| op = PredictOperator( | |
| input_type, | |
| output_type | |
| ) | |
| self._connect(op) | |
| return DataQuanta( | |
| self.context, | |
| that._connect(op, 1) | |
| ) | |
| def train_logistic_regression( | |
| self: "DataQuanta[In]", | |
| labels: "DataQuanta[In]", | |
| fit_intercept: bool = True | |
| ) -> "DataQuanta[Out]": | |
| op = LogisticRegression() | |
| self._connect(op, 0) | |
| labels._connect(op, 1) | |
| return DataQuanta(self.context, op) | |
| def train_decision_tree_regression( | |
| self: "DataQuanta[In]", | |
| labels: "DataQuanta[In]", | |
| max_depth: int = 5, | |
| min_instances: int = 2 | |
| ) -> "DataQuanta[Out]": | |
| op = DecisionTreeRegression(max_depth, min_instances) | |
| self._connect(op, 0) | |
| labels._connect(op, 1) | |
| return DataQuanta(self.context, op) | |
| def train_linear_svc( | |
| self: "DataQuanta[In]", | |
| labels: "DataQuanta[In]", | |
| max_iter: int = 10, | |
| reg_param: float = 0.1 | |
| ) -> "DataQuanta[Out]": | |
| op = LinearSVC(max_iter=max_iter, reg_param=reg_param) | |
| self._connect(op, 0) | |
| labels._connect(op, 1) | |
| return DataQuanta(self.context, op) | |
| def store_textfile(self: "DataQuanta[In]", path: str, input_type: GenericTco = None) -> None: | |
| last: List[SinkOperator] = [ | |
| cast( | |
| SinkOperator, | |
| self._connect( | |
| TextFileSink( | |
| path, | |
| input_type | |
| ) | |
| ) | |
| ) | |
| ] | |
| PywyPlan(self.context.plugins, self.context.configuration, last).execute() | |
| def _connect(self, op: PO_T, port_op: int = 0) -> PywyOperator: | |
| self.operator.connect(0, op, port_op) | |
| return op | |
| def __str__(self): | |
| return str(self.operator) | |
| def __repr__(self): | |
| return self.__str__() |