aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xpython/pyspark/ml/tests.py18
-rw-r--r--python/pyspark/ml/wrapper.py41
2 files changed, 41 insertions, 18 deletions
diff --git a/python/pyspark/ml/tests.py b/python/pyspark/ml/tests.py
index a0c288a0b7..68f5bc30ac 100755
--- a/python/pyspark/ml/tests.py
+++ b/python/pyspark/ml/tests.py
@@ -390,6 +390,24 @@ class ParamTests(PySparkTestCase):
self.assertEqual(model.getWindowSize(), 6)
+class EvaluatorTests(SparkSessionTestCase):
+
+ def test_java_params(self):
+ """
+ This tests a bug fixed by SPARK-18274 which causes multiple copies
+ of a Params instance in Python to be linked to the same Java instance.
+ """
+ evaluator = RegressionEvaluator(metricName="r2")
+ df = self.spark.createDataFrame([Row(label=1.0, prediction=1.1)])
+ evaluator.evaluate(df)
+ self.assertEqual(evaluator._java_obj.getMetricName(), "r2")
+ evaluatorCopy = evaluator.copy({evaluator.metricName: "mae"})
+ evaluator.evaluate(df)
+ evaluatorCopy.evaluate(df)
+ self.assertEqual(evaluator._java_obj.getMetricName(), "r2")
+ self.assertEqual(evaluatorCopy._java_obj.getMetricName(), "mae")
+
+
class FeatureTests(SparkSessionTestCase):
def test_binarizer(self):
diff --git a/python/pyspark/ml/wrapper.py b/python/pyspark/ml/wrapper.py
index 25c44b7533..13b75e9919 100644
--- a/python/pyspark/ml/wrapper.py
+++ b/python/pyspark/ml/wrapper.py
@@ -71,6 +71,10 @@ class JavaParams(JavaWrapper, Params):
__metaclass__ = ABCMeta
+ def __del__(self):
+ if SparkContext._active_spark_context:
+ SparkContext._active_spark_context._gateway.detach(self._java_obj)
+
def _make_java_param_pair(self, param, value):
"""
Makes a Java parm pair.
@@ -180,6 +184,25 @@ class JavaParams(JavaWrapper, Params):
% stage_name)
return py_stage
+ def copy(self, extra=None):
+ """
+ Creates a copy of this instance with the same uid and some
+ extra params. This implementation first calls Params.copy and
+ then make a copy of the companion Java pipeline component with
+ extra params. So both the Python wrapper and the Java pipeline
+ component get copied.
+
+ :param extra: Extra parameters to copy to the new instance
+ :return: Copy of this instance
+ """
+ if extra is None:
+ extra = dict()
+ that = super(JavaParams, self).copy(extra)
+ if self._java_obj is not None:
+ that._java_obj = self._java_obj.copy(self._empty_java_param_map())
+ that._transfer_params_to_java()
+ return that
+
@inherit_doc
class JavaEstimator(JavaParams, Estimator):
@@ -256,21 +279,3 @@ class JavaModel(JavaTransformer, Model):
super(JavaModel, self).__init__(java_model)
if java_model is not None:
self._resetUid(java_model.uid())
-
- def copy(self, extra=None):
- """
- Creates a copy of this instance with the same uid and some
- extra params. This implementation first calls Params.copy and
- then make a copy of the companion Java model with extra params.
- So both the Python wrapper and the Java model get copied.
-
- :param extra: Extra parameters to copy to the new instance
- :return: Copy of this instance
- """
- if extra is None:
- extra = dict()
- that = super(JavaModel, self).copy(extra)
- if self._java_obj is not None:
- that._java_obj = self._java_obj.copy(self._empty_java_param_map())
- that._transfer_params_to_java()
- return that