SDKPYTHON-8 #comment add get_itemsim_topn and version check in test script
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 5d4fcf4..9855198 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -49,9 +49,9 @@
# built documents.
#
# The short X.Y version.
-version = '0.5'
+version = '0.6'
# The full version, including alpha/beta/rc tags.
-release = '0.5.0'
+release = '0.6.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/predictionio/__init__.py b/predictionio/__init__.py
index 2f68cf2..608a1fb 100644
--- a/predictionio/__init__.py
+++ b/predictionio/__init__.py
@@ -9,7 +9,7 @@
__copyright__ = "Copyright 2013, TappingStone, Inc."
__license__ = "Apache License, Version 2.0"
-__version__ = "0.5.0"
+__version__ = "0.6.0-SNAPSHOT"
# import packages
@@ -63,6 +63,10 @@
"Error happened when tried to get item recommendation"
pass
+class ItemSimNotFoundError(PredictionIOAPIError):
+ "Error happened when tried to get similar items"
+ pass
+
class InvalidArgumentError(PredictionIOAPIError):
"Arguments are not valid"
pass
@@ -485,6 +489,69 @@
request = self._aget_user_itemrec_topn(uid, n, engine, params)
return request
+ def _aget_itemsim_topn(self, engine, iid, n, params={}):
+ """Private function to asynchronously get top n similar items of the item
+
+ :param engine: name of the prediction engine. type str.
+ :param iid: item id. type str.
+ :param n: number of similar items. type int.
+ :param params: optional parameters. type dictionary
+ For example, { 'pio_itypes' : ("t1","t2") }
+ :returns:
+ AsyncRequest object. You should call the aresp() method using this AsyncRequest
+ object as argument to get the final result or status of this asynchronous request.
+ """
+ if "pio_itypes" in params:
+ params["pio_itypes"] = ",".join(params["pio_itypes"])
+ if "pio_latlng" in params:
+ params["pio_latlng"] = ",".join(map(str, params["pio_latlng"]))
+ if "pio_attributes" in params:
+ params["pio_attributes"] = ",".join(params["pio_attributes"])
+
+ enc_iid = urllib.quote(iid,"") # replace special char with %xx
+ path = "%s/engines/itemsim/%s/topn.json" % (self.apiversion, engine)
+ request = AsyncRequest("GET", path, pio_appkey=self.appkey, pio_iid=enc_iid, pio_n=n, **params)
+ request.set_rfunc(self._aget_itemsim_topn_resp)
+ self._connection.make_request(request)
+ return request
+
+ def _aget_itemsim_topn_resp(self, response):
+ """Private function to handle the AsyncResponse of the aget_itemsim request
+
+ :param response: AsyncResponse object
+
+ :returns:
+ data in dictionary format.
+
+ :raises:
+ ItemSimNotFoundError.
+ """
+ if response.error is not None:
+ raise ItemSimNotFoundError("Exception happened: %s for request %s" % \
+ (response.error, response.request))
+ elif response.status != httplib.OK:
+ raise ItemSimNotFoundError("request: %s status: %s body: %s" % \
+ (response.request, response.status, response.body))
+
+ data = json.loads(response.body) # convert json string to dict
+ return data
+
+ def aget_itemsim_topn(self, engine, iid, n, params={}):
+ """Asynchronously get top n similar items of the item
+
+ :param engine: name of the prediction engine. type str.
+ :param iid: item id. type str.
+ :param n: number of similar items. type int.
+ :param params: optional parameters. type dictionary
+ For example, { 'pio_itypes' : ("t1",) }
+ :returns:
+ AsyncRequest object. You should call the aresp() method using this AsyncRequest
+ object as argument to get the final result or status of this asynchronous request.
+ """
+
+ request = self._aget_itemsim_topn(engine, iid, n, params)
+ return request
+
def _auser_action_on_item(self, action, uid, iid, params):
"""Private function to asynchronously create an user action on an item
@@ -795,6 +862,25 @@
result = self.aresp(request)
return result
+ def get_itemsim_topn(self, engine, iid, n, params={}):
+ """Blocking request to get top n similar items of the item
+
+ :param engine: name of the prediction engine. type str.
+ :param iid: item id. type str.
+ :param n: number of similar items. type int.
+ :param params: optional parameters. type dictionary
+ For example, { 'pio_itypes' : ("t1",) }
+ :returns:
+ data in dictionary format.
+
+ :raises:
+ ItemSimNotFoundError.
+ """
+
+ request = self.aget_itemsim_topn(engine, iid, n, params)
+ result = self.aresp(request)
+ return result
+
def record_action_on_item(self, action, iid, params={}):
"""Blocking request to create action on an item
diff --git a/tests/import_testdata.py b/tests/import_testdata.py
index 40263e9..add526f 100644
--- a/tests/import_testdata.py
+++ b/tests/import_testdata.py
@@ -3,9 +3,14 @@
"""
import predictionio
-APP_KEY = "zHCx9Xv9sZ9Q21LMINKcrgZNgGJ3oReZA9Zvf0MsyJYDv6FwgHEeEI0XTEY5aEsu"
+APP_KEY = "y2Fk4BACEGYeJnqBF4zL9TmrIBdF9va3gyFaLsnM7PVyUNf0G00zC8vCnyBx5hdA"
API_URL = "http://localhost:8000"
+MIN_VERSION = '0.5.0'
+if predictionio.__version__ < MIN_VERSION:
+ err = "Require PredictionIO Python SDK version >= %s" % MIN_VERSION
+ raise Exception(err)
+
if __name__ == "__main__":
client = predictionio.Client(APP_KEY, 1, API_URL)
diff --git a/tests/predictionio_itemrec_test.py b/tests/predictionio_itemrec_test.py
index 7d39ee5..873cc73 100644
--- a/tests/predictionio_itemrec_test.py
+++ b/tests/predictionio_itemrec_test.py
@@ -14,6 +14,11 @@
DEBUG = True
+MIN_VERSION = '0.6.0'
+if predictionio.__version__ < MIN_VERSION:
+ err = "Require PredictionIO Python SDK version >= %s" % MIN_VERSION
+ raise Exception(err)
+
class TestPredictionIO(unittest.TestCase):
def setUp(self):
pass
diff --git a/tests/predictionio_itemsim_test.py b/tests/predictionio_itemsim_test.py
new file mode 100644
index 0000000..3c27886
--- /dev/null
+++ b/tests/predictionio_itemsim_test.py
@@ -0,0 +1,145 @@
+"""
+Test getting itemsim after algo training completes (pdio-itemsimcf with cosine sim).
+"""
+import predictionio
+import unittest
+import threading
+import time
+
+import httplib
+import urllib
+
+APP_KEY = "y2Fk4BACEGYeJnqBF4zL9TmrIBdF9va3gyFaLsnM7PVyUNf0G00zC8vCnyBx5hdA" # replace this with your AppKey
+API_URL = "http://localhost:8000" # PredictoinIO Server
+
+DEBUG = True
+
+MIN_VERSION = '0.6.0'
+if predictionio.__version__ < MIN_VERSION:
+ err = "Require PredictionIO Python SDK version >= %s" % MIN_VERSION
+ raise Exception(err)
+
+class TestPredictionIO(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def test_get_itemsim(self):
+ client = predictionio.Client(APP_KEY, 1, API_URL)
+
+ # request more than what is available
+ try:
+ itemsim = client.get_itemsim_topn("python-itemsim-engine", "i0", 10)
+ except predictionio.ItemSimNotFoundError as e:
+ print "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?"
+ raise
+ except:
+ raise
+ if DEBUG: print itemsim
+ self.assertTrue( (itemsim == {"pio_iids": ["i1", "i2", "i3"]}) or
+ (itemsim == {"pio_iids": ["i1", "i3", "i2"]}) )
+
+ try:
+ itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 10)
+ except predictionio.ItemSimNotFoundError as e:
+ print "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?"
+ raise
+ except:
+ raise
+ if DEBUG: print itemsim
+ self.assertTrue( (itemsim == {"pio_iids": ["i2", "i3", "i0"]}) )
+
+ try:
+ itemsim = client.get_itemsim_topn("python-itemsim-engine", "i2", 10)
+ except predictionio.ItemSimNotFoundError as e:
+ print "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?"
+ raise
+ except:
+ raise
+ if DEBUG: print itemsim
+ self.assertTrue( (itemsim == {"pio_iids": ["i1", "i3", "i0"]}) )
+
+ try:
+ itemsim = client.get_itemsim_topn("python-itemsim-engine", "i3", 10)
+ except predictionio.ItemSimNotFoundError as e:
+ print "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?"
+ raise
+ except:
+ raise
+ if DEBUG: print itemsim
+ self.assertTrue( (itemsim == {"pio_iids": ["i1", "i2", "i0"]}) )
+
+ # request less
+ try:
+ itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 1)
+ except predictionio.ItemSimNotFoundError as e:
+ print "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?"
+ raise
+ except:
+ raise
+ if DEBUG: print itemsim
+ self.assertEqual(itemsim, {"pio_iids": ["i2"]})
+
+ try:
+ itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 2)
+ except predictionio.ItemSimNotFoundError as e:
+ print "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?"
+ raise
+ except:
+ raise
+ if DEBUG: print itemsim
+ self.assertEqual(itemsim, {"pio_iids": ["i2", "i3"]})
+
+ # request with optional attributes
+
+ # pio_itypes
+ try:
+ itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 10, {"pio_itypes": ("t1","t2")})
+ except predictionio.ItemSimNotFoundError as e:
+ print "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?"
+ raise
+ except:
+ raise
+ if DEBUG: print itemsim
+ self.assertEqual(itemsim, {"pio_iids": ["i2", "i3", "i0"]})
+
+ # subset itypes
+ try:
+ itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 10, {"pio_itypes": ("t2",)})
+ except predictionio.ItemSimNotFoundError as e:
+ print "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?"
+ raise
+ except:
+ raise
+ if DEBUG: print itemsim
+ self.assertEqual(itemsim, {"pio_iids": ["i2"]})
+
+ # nonexisting itypes
+ try:
+ itemsim = client.get_itemsim_topn("python-itemsim-engine", "i0", 10, {"pio_itypes": ("other-itype",)})
+ except predictionio.ItemSimNotFoundError as e:
+ pass # expected no recommendation
+ except:
+ raise
+
+ # pio_attributes
+ try:
+ itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 10, {"pio_itypes": ("t1",), "pio_attributes": ["custom1", "custom2"]})
+ except predictionio.ItemSimNotFoundError as e:
+ print "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?"
+ raise
+ except:
+ raise
+ if DEBUG: print itemsim
+ self.assertEqual(itemsim, {"pio_iids": ["i2", "i3", "i0"], "custom1": [None, None, "i0c1"], "custom2": ["i2c2", None, None]})
+
+ # TODO pio_latlng
+ # TODO pio_within
+ # TODO pio_unit
+
+ client.close()
+
+if __name__ == "__main__" :
+ unittest.main()
diff --git a/tests/predictionio_test.py b/tests/predictionio_test.py
index 41e2ecd..fe919cc 100644
--- a/tests/predictionio_test.py
+++ b/tests/predictionio_test.py
@@ -9,10 +9,14 @@
import httplib
import urllib
-
-APP_KEY = "zHCx9Xv9sZ9Q21LMINKcrgZNgGJ3oReZA9Zvf0MsyJYDv6FwgHEeEI0XTEY5aEsu" # replace this with your AppKey
+APP_KEY = "y2Fk4BACEGYeJnqBF4zL9TmrIBdF9va3gyFaLsnM7PVyUNf0G00zC8vCnyBx5hdA" # replace this with your AppKey
API_URL = "http://localhost:8000" # PredictoinIO Server
+MIN_VERSION = '0.6.0'
+if predictionio.__version__ < MIN_VERSION:
+ err = "Require PredictionIO Python SDK version >= %s" % MIN_VERSION
+ raise Exception(err)
+
class TestPredictionIO(unittest.TestCase):
def setUp(self):
@@ -204,6 +208,25 @@
client.close()
+ def test_get_itemsim_topn(self):
+ client = predictionio.Client(APP_KEY, 1, API_URL)
+
+ try:
+ itemsim = client.get_itemsim_topn("test-python-engine", "i1unknwon", 10)
+ except predictionio.ItemSimNotFoundError as e:
+ pass # expected exception
+ except:
+ raise
+
+ try:
+ itemsim = client.get_itemsim_topn("test-python-engine", "i1unknwon", 10, { "pio_itypes": ("t1",), "pio_latlng": [1.34, 5.67], "pio_within": 5.0, "pio_unit": "km", "pio_attributes": ["custom1", "custom2"] })
+ except predictionio.ItemSimNotFoundError as e:
+ pass # expected exception
+ except:
+ raise
+
+ client.close()
+
"""
to run individual test:
$ python -m unittest predictionio_test.TestPredictionIO.test_user