Repository: incubator-predictionio-site
Updated Branches:
  refs/heads/asf-site 259381690 -> 0bdbf8fef


http://git-wip-us.apache.org/repos/asf/incubator-predictionio-site/blob/0bdbf8fe/templates/recommendation/dase/index.html
----------------------------------------------------------------------
diff --git a/templates/recommendation/dase/index.html 
b/templates/recommendation/dase/index.html
new file mode 100644
index 0000000..a9f7f3e
--- /dev/null
+++ b/templates/recommendation/dase/index.html
@@ -0,0 +1,367 @@
+<!DOCTYPE html><html><head><title>DASE Components Explained 
(Recommendation)</title><meta charset="utf-8"/><meta content="IE=edge,chrome=1" 
http-equiv="X-UA-Compatible"/><meta name="viewport" 
content="width=device-width, initial-scale=1.0"/><meta class="swiftype" 
name="title" data-type="string" content="DASE Components Explained 
(Recommendation)"/><link rel="canonical" 
href="https://docs.prediction.io/templates/recommendation/dase/"/><link 
href="/images/favicon/normal-b330020a.png" rel="shortcut icon"/><link 
href="/images/favicon/apple-c0febcf2.png" rel="apple-touch-icon"/><link 
href="//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800"
 rel="stylesheet"/><link 
href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" 
rel="stylesheet"/><link href="/stylesheets/application-a2a2f408.css" 
rel="stylesheet" type="text/css"/><script 
src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.min.js"></scri
 pt><script 
src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script><script
 src="//use.typekit.net/pqo0itb.js"></script><script>try{Typekit.load({ async: 
true });}catch(e){}</script></head><body><div id="global"><header><div 
class="container" id="header-wrapper"><div class="row"><div 
class="col-sm-12"><div id="logo-wrapper"><span id="drawer-toggle"></span><a 
href="#"></a><a href="http://predictionio.incubator.apache.org/";><img 
alt="PredictionIO" id="logo" 
src="/images/logos/logo-ee2b9bb3.png"/></a></div><div id="menu-wrapper"><div 
id="pill-wrapper"><a class="pill left" 
href="/gallery/template-gallery">TEMPLATES</a> <a class="pill right" 
href="//github.com/apache/incubator-predictionio/">OPEN 
SOURCE</a></div></div><img class="mobile-search-bar-toggler hidden-md 
hidden-lg" 
src="/images/icons/search-glass-704bd4ff.png"/></div></div></div></header><div 
id="search-bar-row-wrapper"><div class="container-fluid" 
id="search-bar-row"><div class="row"><div class=
 "col-md-9 col-sm-11 col-xs-11"><div class="hidden-md hidden-lg" 
id="mobile-page-heading-wrapper"><p>PredictionIO Docs</p><h4>DASE Components 
Explained (Recommendation)</h4></div><h4 class="hidden-sm 
hidden-xs">PredictionIO Docs</h4></div><div class="col-md-3 col-sm-1 col-xs-1 
hidden-md hidden-lg"><img id="left-menu-indicator" 
src="/images/icons/down-arrow-dfe9f7fe.png"/></div><div class="col-md-3 
col-sm-12 col-xs-12 swiftype-wrapper"><div class="swiftype"><form 
class="search-form"><img class="search-box-toggler hidden-xs hidden-sm" 
src="/images/icons/search-glass-704bd4ff.png"/><div class="search-box"><img 
src="/images/icons/search-glass-704bd4ff.png"/><input type="text" 
id="st-search-input" class="st-search-input" placeholder="Search 
Doc..."/></div><img class="swiftype-row-hider hidden-md hidden-lg" 
src="/images/icons/drawer-toggle-active-fcbef12a.png"/></form></div></div><div 
class="mobile-left-menu-toggler hidden-md 
hidden-lg"></div></div></div></div><div id="page" class="contain
 er-fluid"><div class="row"><div id="left-menu-wrapper" class="col-md-3"><nav 
id="nav-main"><ul><li class="level-1"><a class="expandible" 
href="/"><span>Apache PredictionIO (incubating) Documentation</span></a><ul><li 
class="level-2"><a class="final" href="/"><span>Welcome to Apache PredictionIO 
(incubating)</span></a></li></ul></li><li class="level-1"><a class="expandible" 
href="#"><span>Getting Started</span></a><ul><li class="level-2"><a 
class="final" href="/start/"><span>A Quick Intro</span></a></li><li 
class="level-2"><a class="final" href="/install/"><span>Installing Apache 
PredictionIO (incubating)</span></a></li><li class="level-2"><a class="final" 
href="/start/download/"><span>Downloading an Engine Template</span></a></li><li 
class="level-2"><a class="final" href="/start/deploy/"><span>Deploying Your 
First Engine</span></a></li><li class="level-2"><a class="final" 
href="/start/customize/"><span>Customizing the 
Engine</span></a></li></ul></li><li class="level-1"><a class="exp
 andible" href="#"><span>Integrating with Your App</span></a><ul><li 
class="level-2"><a class="final" href="/appintegration/"><span>App Integration 
Overview</span></a></li><li class="level-2"><a class="expandible" 
href="/sdk/"><span>List of SDKs</span></a><ul><li class="level-3"><a 
class="final" href="/sdk/java/"><span>Java & Android SDK</span></a></li><li 
class="level-3"><a class="final" href="/sdk/php/"><span>PHP 
SDK</span></a></li><li class="level-3"><a class="final" 
href="/sdk/python/"><span>Python SDK</span></a></li><li class="level-3"><a 
class="final" href="/sdk/ruby/"><span>Ruby SDK</span></a></li><li 
class="level-3"><a class="final" href="/sdk/community/"><span>Community Powered 
SDKs</span></a></li></ul></li></ul></li><li class="level-1"><a 
class="expandible" href="#"><span>Deploying an Engine</span></a><ul><li 
class="level-2"><a class="final" href="/deploy/"><span>Deploying as a Web 
Service</span></a></li><li class="level-2"><a class="final" 
href="/cli/#engine-commands"><spa
 n>Engine Command-line Interface</span></a></li><li class="level-2"><a 
class="final" href="/deploy/monitoring/"><span>Monitoring 
Engine</span></a></li><li class="level-2"><a class="final" 
href="/deploy/engineparams/"><span>Setting Engine Parameters</span></a></li><li 
class="level-2"><a class="final" href="/deploy/enginevariants/"><span>Deploying 
Multiple Engine Variants</span></a></li></ul></li><li class="level-1"><a 
class="expandible" href="#"><span>Customizing an Engine</span></a><ul><li 
class="level-2"><a class="final" href="/customize/"><span>Learning 
DASE</span></a></li><li class="level-2"><a class="final" 
href="/customize/dase/"><span>Implement DASE</span></a></li><li 
class="level-2"><a class="final" 
href="/customize/troubleshooting/"><span>Troubleshooting Engine 
Development</span></a></li><li class="level-2"><a class="final" 
href="/api/current/#package"><span>Engine Scala 
APIs</span></a></li></ul></li><li class="level-1"><a class="expandible" 
href="#"><span>Collecting and Anal
 yzing Data</span></a><ul><li class="level-2"><a class="final" 
href="/datacollection/"><span>Event Server Overview</span></a></li><li 
class="level-2"><a class="final" href="/cli/#event-server-commands"><span>Event 
Server Command-line Interface</span></a></li><li class="level-2"><a 
class="final" href="/datacollection/eventapi/"><span>Collecting Data with 
REST/SDKs</span></a></li><li class="level-2"><a class="final" 
href="/datacollection/eventmodel/"><span>Events Modeling</span></a></li><li 
class="level-2"><a class="final" 
href="/datacollection/webhooks/"><span>Unifying Multichannel Data with 
Webhooks</span></a></li><li class="level-2"><a class="final" 
href="/datacollection/channel/"><span>Channel</span></a></li><li 
class="level-2"><a class="final" 
href="/datacollection/batchimport/"><span>Importing Data in 
Batch</span></a></li><li class="level-2"><a class="final" 
href="/datacollection/analytics/"><span>Using Analytics 
Tools</span></a></li></ul></li><li class="level-1"><a class="expand
 ible" href="#"><span>Choosing an Algorithm(s)</span></a><ul><li 
class="level-2"><a class="final" href="/algorithm/"><span>Built-in Algorithm 
Libraries</span></a></li><li class="level-2"><a class="final" 
href="/algorithm/switch/"><span>Switching to Another 
Algorithm</span></a></li><li class="level-2"><a class="final" 
href="/algorithm/multiple/"><span>Combining Multiple 
Algorithms</span></a></li><li class="level-2"><a class="final" 
href="/algorithm/custom/"><span>Adding Your Own 
Algorithms</span></a></li></ul></li><li class="level-1"><a class="expandible" 
href="#"><span>ML Tuning and Evaluation</span></a><ul><li class="level-2"><a 
class="final" href="/evaluation/"><span>Overview</span></a></li><li 
class="level-2"><a class="final" 
href="/evaluation/paramtuning/"><span>Hyperparameter Tuning</span></a></li><li 
class="level-2"><a class="final" 
href="/evaluation/evaluationdashboard/"><span>Evaluation 
Dashboard</span></a></li><li class="level-2"><a class="final" 
href="/evaluation/metricchoo
 se/"><span>Choosing Evaluation Metrics</span></a></li><li class="level-2"><a 
class="final" href="/evaluation/metricbuild/"><span>Building Evaluation 
Metrics</span></a></li></ul></li><li class="level-1"><a class="expandible" 
href="#"><span>System Architecture</span></a><ul><li class="level-2"><a 
class="final" href="/system/"><span>Architecture Overview</span></a></li><li 
class="level-2"><a class="final" href="/system/anotherdatastore/"><span>Using 
Another Data Store</span></a></li></ul></li><li class="level-1"><a 
class="expandible" href="#"><span>Engine Template Gallery</span></a><ul><li 
class="level-2"><a class="final" 
href="/gallery/template-gallery/"><span>Browse</span></a></li><li 
class="level-2"><a class="final" 
href="/community/submit-template/"><span>Submit your Engine as a 
Template</span></a></li></ul></li><li class="level-1"><a class="expandible" 
href="#"><span>Demo Tutorials</span></a><ul><li class="level-2"><a 
class="final" href="/demo/tapster/"><span>Comics Recommendation
  Demo</span></a></li><li class="level-2"><a class="final" 
href="/demo/community/"><span>Community Contributed Demo</span></a></li><li 
class="level-2"><a class="final" href="/demo/textclassification/"><span>Text 
Classification Engine Tutorial</span></a></li></ul></li><li class="level-1"><a 
class="expandible" href="/community/"><span>Getting Involved</span></a><ul><li 
class="level-2"><a class="final" 
href="/community/contribute-code/"><span>Contribute Code</span></a></li><li 
class="level-2"><a class="final" 
href="/community/contribute-documentation/"><span>Contribute 
Documentation</span></a></li><li class="level-2"><a class="final" 
href="/community/contribute-sdk/"><span>Contribute a SDK</span></a></li><li 
class="level-2"><a class="final" 
href="/community/contribute-webhook/"><span>Contribute a 
Webhook</span></a></li><li class="level-2"><a class="final" 
href="/community/projects/"><span>Community 
Projects</span></a></li></ul></li><li class="level-1"><a class="expandible" 
href="#"><spa
 n>Getting Help</span></a><ul><li class="level-2"><a class="final" 
href="/resources/faq/"><span>FAQs</span></a></li><li class="level-2"><a 
class="final" href="/support/"><span>Support</span></a></li></ul></li><li 
class="level-1"><a class="expandible" 
href="#"><span>Resources</span></a><ul><li class="level-2"><a class="final" 
href="/resources/intellij/"><span>Developing Engines with IntelliJ 
IDEA</span></a></li><li class="level-2"><a class="final" 
href="/resources/upgrade/"><span>Upgrade Instructions</span></a></li><li 
class="level-2"><a class="final" 
href="/resources/glossary/"><span>Glossary</span></a></li></ul></li></ul></nav></div><div
 class="col-md-9 col-sm-12"><div class="content-header hidden-md 
hidden-lg"><div id="page-title"><h1>DASE Components Explained 
(Recommendation)</h1></div></div><div id="table-of-content-wrapper"><h5>On this 
page</h5><aside id="table-of-contents"><ul> <li> <a 
href="#the-engine-design">The Engine Design</a> </li> <li> <a 
href="#data">Data</a> </li> <li
 > <a href="#algorithm">Algorithm</a> </li> <li> <a href="#serving">Serving</a> 
 > </li> </ul> </aside><hr/><a id="edit-page-link" 
 > href="https://github.com/apache/incubator-predictionio/tree/livedoc/docs/manual/source/templates/recommendation/dase.html.md.erb";><img
 >  src="/images/icons/edit-pencil-d6c1bb3d.png"/>Edit this page</a></div><div 
 > class="content-header hidden-sm hidden-xs"><div id="page-title"><h1>DASE 
 > Components Explained (Recommendation)</h1></div></div><div 
 > class="content"><p>PredictionIO&#39;s DASE architecture brings the 
 > separation-of-concerns design principle to predictive engine development. 
 > DASE stands for the following components of an engine:</p> <ul> 
 > <li><strong>D</strong>ata - includes Data Source and Data Preparator</li> 
 > <li><strong>A</strong>lgorithm(s)</li> <li><strong>S</strong>erving</li> 
 > <li><strong>E</strong>valuator</li> </ul> <p><p>Let&#39;s look at the code 
 > and see how you can customize the engine you built from the Recommendation 
 > Engine Template.</p><div c
 lass="alert-message note"><p>Evaluator will not be covered in this tutorial. 
Please visit <a href="/templates/recommendation/evaluation/">evaluation 
explained</a> for using evaluation.</p></div></p><h2 id='the-engine-design' 
class='header-anchors'>The Engine Design</h2><p>As you can see from the Quick 
Start, <em>MyRecommendation</em> takes a JSON prediction query, e.g. <code>{ 
&quot;user&quot;: &quot;1&quot;, &quot;num&quot;: 4 }</code>, and return a JSON 
predicted result. In 
MyRecommendation/src/main/scala/<strong><em>Engine.scala</em></strong>, the 
<code>Query</code> case class defines the format of such 
<strong>query</strong>:</p><div class="highlight scala"><table 
style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: 
right"><pre class="lineno">1
+2
+3
+4</pre></td><td class="code"><pre><span class="k">case</span> <span 
class="k">class</span> <span class="nc">Query</span><span class="o">(</span>
+  <span class="n">user</span><span class="k">:</span> <span 
class="kt">String</span><span class="o">,</span>
+  <span class="n">num</span><span class="k">:</span> <span 
class="kt">Int</span>
+<span class="o">)</span> <span class="k">extends</span> <span 
class="nc">Serializable</span>
+</pre></td></tr></tbody></table> </div> <p>The <code>PredictedResult</code> 
case class defines the format of <strong>predicted result</strong>, such 
as</p><div class="highlight json"><table style="border-spacing: 
0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre 
class="lineno">1
+2
+3
+4
+5
+6</pre></td><td class="code"><pre><span class="p">{</span><span 
class="s2">"itemScores"</span><span class="p">:[</span><span class="w">
+  </span><span class="p">{</span><span class="s2">"item"</span><span 
class="p">:</span><span class="mi">22</span><span class="p">,</span><span 
class="s2">"score"</span><span class="p">:</span><span 
class="mf">4.07</span><span class="p">},</span><span class="w">
+  </span><span class="p">{</span><span class="s2">"item"</span><span 
class="p">:</span><span class="mi">62</span><span class="p">,</span><span 
class="s2">"score"</span><span class="p">:</span><span 
class="mf">4.05</span><span class="p">},</span><span class="w">
+  </span><span class="p">{</span><span class="s2">"item"</span><span 
class="p">:</span><span class="mi">75</span><span class="p">,</span><span 
class="s2">"score"</span><span class="p">:</span><span 
class="mf">4.04</span><span class="p">},</span><span class="w">
+  </span><span class="p">{</span><span class="s2">"item"</span><span 
class="p">:</span><span class="mi">68</span><span class="p">,</span><span 
class="s2">"score"</span><span class="p">:</span><span 
class="mf">3.81</span><span class="p">}</span><span class="w">
+</span><span class="p">]}</span><span class="w">
+</span></pre></td></tr></tbody></table> </div> <p>with:</p><div 
class="highlight scala"><table style="border-spacing: 0"><tbody><tr><td 
class="gutter gl" style="text-align: right"><pre class="lineno">1
+2
+3
+4
+5
+6
+7
+8</pre></td><td class="code"><pre><span class="k">case</span> <span 
class="k">class</span> <span class="nc">PredictedResult</span><span 
class="o">(</span>
+  <span class="n">itemScores</span><span class="k">:</span> <span 
class="kt">Array</span><span class="o">[</span><span 
class="kt">ItemScore</span><span class="o">]</span>
+<span class="o">)</span> <span class="k">extends</span> <span 
class="nc">Serializable</span>
+
+<span class="k">case</span> <span class="k">class</span> <span 
class="nc">ItemScore</span><span class="o">(</span>
+  <span class="n">item</span><span class="k">:</span> <span 
class="kt">String</span><span class="o">,</span>
+  <span class="n">score</span><span class="k">:</span> <span 
class="kt">Double</span>
+<span class="o">)</span> <span class="k">extends</span> <span 
class="nc">Serializable</span>
+</pre></td></tr></tbody></table> </div> <p>Finally, 
<code>RecommendationEngine</code> is the <em>Engine Factory</em> that defines 
the components this engine will use: Data Source, Data Preparator, Algorithm(s) 
and Serving components.</p><div class="highlight scala"><table 
style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: 
right"><pre class="lineno">1
+2
+3
+4
+5
+6
+7
+8
+9
+10</pre></td><td class="code"><pre><span class="k">object</span> <span 
class="nc">RecommendationEngine</span> <span class="k">extends</span> <span 
class="nc">IEngineFactory</span> <span class="o">{</span>
+  <span class="k">def</span> <span class="n">apply</span><span 
class="o">()</span> <span class="k">=</span> <span class="o">{</span>
+    <span class="k">new</span> <span class="nc">Engine</span><span 
class="o">(</span>
+      <span class="n">classOf</span><span class="o">[</span><span 
class="kt">DataSource</span><span class="o">],</span>
+      <span class="n">classOf</span><span class="o">[</span><span 
class="kt">Preparator</span><span class="o">],</span>
+      <span class="nc">Map</span><span class="o">(</span><span 
class="s">"als"</span> <span class="o">-&gt;</span> <span 
class="n">classOf</span><span class="o">[</span><span 
class="kt">ALSAlgorithm</span><span class="o">]),</span>
+      <span class="n">classOf</span><span class="o">[</span><span 
class="kt">Serving</span><span class="o">])</span>
+  <span class="o">}</span>
+  <span class="o">...</span>
+<span class="o">}</span>
+</pre></td></tr></tbody></table> </div> <h3 id='spark-mllib' 
class='header-anchors'>Spark MLlib</h3><p>Spark&#39;s MLlib ALS algorithm takes 
training data of RDD type, i.e. <code>RDD[Rating]</code> and train a model, 
which is a <code>MatrixFactorizationModel</code> object.</p><p>PredictionIO 
Recommendation Engine Template, which <em>MyRecommendation</em> bases on, 
integrates this algorithm under the DASE architecture. We will take a closer 
look at the DASE code below.</p><div class="alert-message info"><p><a 
href="https://spark.apache.org/docs/latest/mllib-collaborative-filtering.html";>Check
 this out</a> to learn more about MLlib&#39;s ALS collaborative filtering 
algorithm.</p></div><h2 id='data' class='header-anchors'>Data</h2><p>In the 
DASE architecture, data is prepared by 2 components sequentially: <em>Data 
Source</em> and <em>Data Preparator</em>. <em>Data Source</em> and <em>Data 
Preparator</em> takes data from the data store and prepares 
<code>RDD[Rating]</code> for the ALS a
 lgorithm.</p><h3 id='data-source' class='header-anchors'>Data Source</h3><p>In 
MyRecommendation/src/main/scala/<strong><em>DataSource.scala</em></strong>, the 
<code>readTraining</code> method of class <code>DataSource</code> reads, and 
selects, data from the <em>Event Store</em> (data store of the <em>Event 
Server</em>) and returns <code>TrainingData</code>.</p><div class="highlight 
scala"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" 
style="text-align: right"><pre class="lineno">1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46</pre></td><td class="code"><pre><span class="k">case</span> <span 
class="k">class</span> <span class="nc">DataSourceParams</span><span 
class="o">(</span><span class="n">appName</span><span class="k">:</span> <span 
class="kt">String</span><span class="o">)</span> <span class="k">extends</span> 
<span class="nc">Params</span>
+
+<span class="k">class</span> <span class="nc">DataSource</span><span 
class="o">(</span><span class="k">val</span> <span class="n">dsp</span><span 
class="k">:</span> <span class="kt">DataSourceParams</span><span 
class="o">)</span>
+  <span class="k">extends</span> <span class="nc">PDataSource</span><span 
class="o">[</span><span class="kt">TrainingData</span>,
+      <span class="kt">EmptyEvaluationInfo</span>, <span 
class="kt">Query</span>, <span class="kt">EmptyActualResult</span><span 
class="o">]</span> <span class="o">{</span>
+
+  <span class="nd">@transient</span> <span class="k">lazy</span> <span 
class="k">val</span> <span class="n">logger</span> <span class="k">=</span> 
<span class="nc">Logger</span><span class="o">[</span><span 
class="kt">this.</span><span class="k">type</span><span class="o">]</span>
+
+  <span class="k">def</span> <span class="n">getRatings</span><span 
class="o">(</span><span class="n">sc</span><span class="k">:</span> <span 
class="kt">SparkContext</span><span class="o">)</span><span class="k">:</span> 
<span class="kt">RDD</span><span class="o">[</span><span 
class="kt">Rating</span><span class="o">]</span> <span class="k">=</span> <span 
class="o">{</span>
+
+    <span class="k">val</span> <span class="n">eventsRDD</span><span 
class="k">:</span> <span class="kt">RDD</span><span class="o">[</span><span 
class="kt">Event</span><span class="o">]</span> <span class="k">=</span> <span 
class="nc">PEventStore</span><span class="o">.</span><span 
class="n">find</span><span class="o">(</span>
+      <span class="n">appName</span> <span class="k">=</span> <span 
class="n">dsp</span><span class="o">.</span><span class="n">appName</span><span 
class="o">,</span>
+      <span class="n">entityType</span> <span class="k">=</span> <span 
class="nc">Some</span><span class="o">(</span><span 
class="s">"user"</span><span class="o">),</span>
+      <span class="n">eventNames</span> <span class="k">=</span> <span 
class="nc">Some</span><span class="o">(</span><span class="nc">List</span><span 
class="o">(</span><span class="s">"rate"</span><span class="o">,</span> <span 
class="s">"buy"</span><span class="o">)),</span> <span class="c1">// read 
"rate" and "buy" event
+</span>      <span class="c1">// targetEntityType is optional field of an 
event.
+</span>      <span class="n">targetEntityType</span> <span class="k">=</span> 
<span class="nc">Some</span><span class="o">(</span><span 
class="nc">Some</span><span class="o">(</span><span 
class="s">"item"</span><span class="o">)))(</span><span 
class="n">sc</span><span class="o">)</span>
+
+    <span class="k">val</span> <span class="n">ratingsRDD</span><span 
class="k">:</span> <span class="kt">RDD</span><span class="o">[</span><span 
class="kt">Rating</span><span class="o">]</span> <span class="k">=</span> <span 
class="n">eventsRDD</span><span class="o">.</span><span class="n">map</span> 
<span class="o">{</span> <span class="n">event</span> <span 
class="k">=&gt;</span>
+      <span class="k">val</span> <span class="n">rating</span> <span 
class="k">=</span> <span class="k">try</span> <span class="o">{</span>
+        <span class="k">val</span> <span class="n">ratingValue</span><span 
class="k">:</span> <span class="kt">Double</span> <span class="o">=</span> 
<span class="n">event</span><span class="o">.</span><span 
class="n">event</span> <span class="k">match</span> <span class="o">{</span>
+          <span class="k">case</span> <span class="s">"rate"</span> <span 
class="k">=&gt;</span> <span class="n">event</span><span 
class="o">.</span><span class="n">properties</span><span 
class="o">.</span><span class="n">get</span><span class="o">[</span><span 
class="kt">Double</span><span class="o">](</span><span 
class="s">"rating"</span><span class="o">)</span>
+          <span class="k">case</span> <span class="s">"buy"</span> <span 
class="k">=&gt;</span> <span class="mf">4.0</span> <span class="c1">// map buy 
event to rating value of 4
+</span>          <span class="k">case</span> <span class="k">_</span> <span 
class="k">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> 
<span class="nc">Exception</span><span class="o">(</span><span 
class="n">s</span><span class="s">"Unexpected event ${event} is 
read."</span><span class="o">)</span>
+        <span class="o">}</span>
+        <span class="c1">// entityId and targetEntityId is String
+</span>        <span class="nc">Rating</span><span class="o">(</span><span 
class="n">event</span><span class="o">.</span><span 
class="n">entityId</span><span class="o">,</span>
+          <span class="n">event</span><span class="o">.</span><span 
class="n">targetEntityId</span><span class="o">.</span><span 
class="n">get</span><span class="o">,</span>
+          <span class="n">ratingValue</span><span class="o">)</span>
+      <span class="o">}</span> <span class="k">catch</span> <span 
class="o">{</span>
+        <span class="k">case</span> <span class="n">e</span><span 
class="k">:</span> <span class="kt">Exception</span> <span 
class="o">=&gt;</span> <span class="o">{</span>
+          <span class="n">logger</span><span class="o">.</span><span 
class="n">error</span><span class="o">(</span><span class="n">s</span><span 
class="s">"Cannot convert ${event} to Rating. Exception: ${e}."</span><span 
class="o">)</span>
+          <span class="k">throw</span> <span class="n">e</span>
+        <span class="o">}</span>
+      <span class="o">}</span>
+      <span class="n">rating</span>
+    <span class="o">}.</span><span class="n">cache</span><span 
class="o">()</span>
+
+    <span class="n">ratingsRDD</span>
+  <span class="o">}</span>
+
+  <span class="k">override</span>
+  <span class="k">def</span> <span class="n">readTraining</span><span 
class="o">(</span><span class="n">sc</span><span class="k">:</span> <span 
class="kt">SparkContext</span><span class="o">)</span><span class="k">:</span> 
<span class="kt">TrainingData</span> <span class="o">=</span> <span 
class="o">{</span>
+    <span class="k">new</span> <span class="nc">TrainingData</span><span 
class="o">(</span><span class="n">getRatings</span><span 
class="o">(</span><span class="n">sc</span><span class="o">))</span>
+  <span class="o">}</span>
+
+<span class="o">}</span>
+</pre></td></tr></tbody></table> </div> <p><code>PEventStore</code> is an 
object which provides function to access data that is collected by PredictionIO 
<em>Event Server</em>. <code>PEventStore.find(...)</code> specifies the events 
that you want to read. PredictionIO automatically loads the parameters of 
<em>datasource</em> specified in 
MyRecommendation/<strong><em>engine.json</em></strong>, including 
<em>appName</em>, to <code>dsp</code>.</p><p>In 
<strong><em>engine.json</em></strong>:</p><div class="highlight shell"><table 
style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: 
right"><pre class="lineno">1
+2
+3
+4
+5
+6
+7
+8
+9</pre></td><td class="code"><pre><span class="o">{</span>
+  ...
+  <span class="s2">"datasource"</span>: <span class="o">{</span>
+    <span class="s2">"params"</span> : <span class="o">{</span>
+      <span class="s2">"appName"</span>: <span class="s2">"MyApp1"</span>
+    <span class="o">}</span>
+  <span class="o">}</span>,
+  ...
+<span class="o">}</span>
+</pre></td></tr></tbody></table> </div> <p>Each <em>rate</em> and <em>buy</em> 
user event data is read as <code>Rating</code>. For flexibility, this 
Recommendation engine template is designed to support user ID and item ID in 
<code>String</code>. Since Spark MLlib&#39;s <code>Rating</code> class assumes 
<code>Int</code>-only user ID and item ID, you have to define a new 
<code>Rating</code> class:</p><div class="highlight scala"><table 
style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: 
right"><pre class="lineno">1
+2
+3
+4
+5</pre></td><td class="code"><pre><span class="k">case</span> <span 
class="k">class</span> <span class="nc">Rating</span><span class="o">(</span>
+  <span class="n">user</span><span class="k">:</span> <span 
class="kt">String</span><span class="o">,</span>
+  <span class="n">item</span><span class="k">:</span> <span 
class="kt">String</span><span class="o">,</span>
+  <span class="n">rating</span><span class="k">:</span> <span 
class="kt">Double</span>
+<span class="o">)</span>
+</pre></td></tr></tbody></table> </div> <p><code>TrainingData</code> contains 
an RDD of all these <code>Rating</code> events. The class definition of 
<code>TrainingData</code> is:</p><div class="highlight scala"><table 
style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: 
right"><pre class="lineno">1
+2
+3</pre></td><td class="code"><pre><span class="k">class</span> <span 
class="nc">TrainingData</span><span class="o">(</span>
+  <span class="k">val</span> <span class="n">ratings</span><span 
class="k">:</span> <span class="kt">RDD</span><span class="o">[</span><span 
class="kt">Rating</span><span class="o">]</span>
+<span class="o">)</span> <span class="k">extends</span> <span 
class="nc">Serializable</span> <span class="o">{...}</span>
+</pre></td></tr></tbody></table> </div> <p>and PredictionIO passes the 
returned <code>TrainingData</code> object to <em>Data Preparator</em>.</p> <div 
class="alert-message info"><p>You could <a 
href="/templates/recommendation/reading-custom-events/">modify the DataSource 
to read custom events</a> other than the default <strong>rate</strong> and 
<strong>buy</strong>.</p></div><h3 id='data-preparator' 
class='header-anchors'>Data Preparator</h3><p>In 
MyRecommendation/src/main/scala/<strong><em>Preparator.scala</em></strong>, the 
<code>prepare</code> method of class <code>Preparator</code> takes 
<code>TrainingData</code> as its input and performs any necessary feature 
selection and data processing tasks. At the end, it returns 
<code>PreparedData</code> which should contain the data <em>Algorithm</em> 
needs. For MLlib ALS, it is <code>RDD[Rating]</code>.</p><p>By default, 
<code>prepare</code> simply copies the unprocessed <code>TrainingData</code> 
data to <code>PreparedData</code>:</p><d
 iv class="highlight scala"><table style="border-spacing: 0"><tbody><tr><td 
class="gutter gl" style="text-align: right"><pre class="lineno">1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11</pre></td><td class="code"><pre><span class="k">class</span> <span 
class="nc">Preparator</span>
+  <span class="k">extends</span> <span class="nc">PPreparator</span><span 
class="o">[</span><span class="kt">TrainingData</span>, <span 
class="kt">PreparedData</span><span class="o">]</span> <span class="o">{</span>
+
+  <span class="k">def</span> <span class="n">prepare</span><span 
class="o">(</span><span class="n">sc</span><span class="k">:</span> <span 
class="kt">SparkContext</span><span class="o">,</span> <span 
class="n">trainingData</span><span class="k">:</span> <span 
class="kt">TrainingData</span><span class="o">)</span><span class="k">:</span> 
<span class="kt">PreparedData</span> <span class="o">=</span> <span 
class="o">{</span>
+    <span class="k">new</span> <span class="nc">PreparedData</span><span 
class="o">(</span><span class="n">ratings</span> <span class="k">=</span> <span 
class="n">trainingData</span><span class="o">.</span><span 
class="n">ratings</span><span class="o">)</span>
+  <span class="o">}</span>
+<span class="o">}</span>
+
+<span class="k">class</span> <span class="nc">PreparedData</span><span 
class="o">(</span>
+  <span class="k">val</span> <span class="n">ratings</span><span 
class="k">:</span> <span class="kt">RDD</span><span class="o">[</span><span 
class="kt">Rating</span><span class="o">]</span>
+<span class="o">)</span> <span class="k">extends</span> <span 
class="nc">Serializable</span>
+</pre></td></tr></tbody></table> </div> <p>PredictionIO passes the returned 
<code>PreparedData</code> object to Algorithm&#39;s <code>train</code> 
function.</p> <h2 id='algorithm' class='header-anchors'>Algorithm</h2><p>In 
MyRecommendation/src/main/scala/<strong><em>ALSAlgorithm.scala</em></strong>, 
the two methods of the algorithm class are <code>train</code> and 
<code>predict</code>. <code>train</code> is responsible for training a 
predictive model. PredictionIO will store this model and <code>predict</code> 
is responsible for using this model to make prediction.</p><h3 id='train(...)' 
class='header-anchors'>train(...)</h3><p><code>train</code> is called when you 
run <strong>pio train</strong>. This is where MLlib ALS algorithm, i.e. 
<code>ALS.train</code>, is used to train a predictive model.</p><div 
class="highlight scala"><table style="border-spacing: 0"><tbody><tr><td 
class="gutter gl" style="text-align: right"><pre class="lineno">1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39</pre></td><td class="code"><pre>  <span class="k">def</span> <span 
class="n">train</span><span class="o">(</span><span class="n">sc</span><span 
class="k">:</span> <span class="kt">SparkContext</span><span class="o">,</span> 
<span class="n">data</span><span class="k">:</span> <span 
class="kt">PreparedData</span><span class="o">)</span><span class="k">:</span> 
<span class="kt">ALSModel</span> <span class="o">=</span> <span 
class="o">{</span>
+    <span class="o">...</span>
+    <span class="c1">// Convert user and item String IDs to Int index for MLlib
+</span>    <span class="k">val</span> <span class="n">userStringIntMap</span> 
<span class="k">=</span> <span class="nc">BiMap</span><span 
class="o">.</span><span class="n">stringInt</span><span class="o">(</span><span 
class="n">data</span><span class="o">.</span><span 
class="n">ratings</span><span class="o">.</span><span class="n">map</span><span 
class="o">(</span><span class="k">_</span><span class="o">.</span><span 
class="n">user</span><span class="o">))</span>
+    <span class="k">val</span> <span class="n">itemStringIntMap</span> <span 
class="k">=</span> <span class="nc">BiMap</span><span class="o">.</span><span 
class="n">stringInt</span><span class="o">(</span><span 
class="n">data</span><span class="o">.</span><span 
class="n">ratings</span><span class="o">.</span><span class="n">map</span><span 
class="o">(</span><span class="k">_</span><span class="o">.</span><span 
class="n">item</span><span class="o">))</span>
+    <span class="k">val</span> <span class="n">mllibRatings</span> <span 
class="k">=</span> <span class="n">data</span><span class="o">.</span><span 
class="n">ratings</span><span class="o">.</span><span class="n">map</span><span 
class="o">(</span> <span class="n">r</span> <span class="k">=&gt;</span>
+      <span class="c1">// MLlibRating requires integer index for user and item
+</span>      <span class="nc">MLlibRating</span><span class="o">(</span><span 
class="n">userStringIntMap</span><span class="o">(</span><span 
class="n">r</span><span class="o">.</span><span class="n">user</span><span 
class="o">),</span> <span class="n">itemStringIntMap</span><span 
class="o">(</span><span class="n">r</span><span class="o">.</span><span 
class="n">item</span><span class="o">),</span> <span class="n">r</span><span 
class="o">.</span><span class="n">rating</span><span class="o">)</span>
+    <span class="o">)</span>
+
+    <span class="c1">// seed for MLlib ALS
+</span>    <span class="k">val</span> <span class="n">seed</span> <span 
class="k">=</span> <span class="n">ap</span><span class="o">.</span><span 
class="n">seed</span><span class="o">.</span><span 
class="n">getOrElse</span><span class="o">(</span><span 
class="nc">System</span><span class="o">.</span><span 
class="n">nanoTime</span><span class="o">)</span>
+
+    <span class="c1">// If you only have one type of implicit event (Eg. 
"view" event only),
+</span>    <span class="c1">// replace ALS.train(...) with
+</span>    <span class="c1">//val m = ALS.trainImplicit(
+</span>      <span class="c1">//ratings = mllibRatings,
+</span>      <span class="c1">//rank = ap.rank,
+</span>      <span class="c1">//iterations = ap.numIterations,
+</span>      <span class="c1">//lambda = ap.lambda,
+</span>      <span class="c1">//blocks = -1,
+</span>      <span class="c1">//alpha = 1.0,
+</span>      <span class="c1">//seed = seed)
+</span>
+    <span class="k">val</span> <span class="n">m</span> <span 
class="k">=</span> <span class="nc">ALS</span><span class="o">.</span><span 
class="n">train</span><span class="o">(</span>
+      <span class="n">ratings</span> <span class="k">=</span> <span 
class="n">mllibRatings</span><span class="o">,</span>
+      <span class="n">rank</span> <span class="k">=</span> <span 
class="n">ap</span><span class="o">.</span><span class="n">rank</span><span 
class="o">,</span>
+      <span class="n">iterations</span> <span class="k">=</span> <span 
class="n">ap</span><span class="o">.</span><span 
class="n">numIterations</span><span class="o">,</span>
+      <span class="n">lambda</span> <span class="k">=</span> <span 
class="n">ap</span><span class="o">.</span><span class="n">lambda</span><span 
class="o">,</span>
+      <span class="n">blocks</span> <span class="k">=</span> <span 
class="o">-</span><span class="mi">1</span><span class="o">,</span>
+      <span class="n">seed</span> <span class="k">=</span> <span 
class="n">seed</span><span class="o">)</span>
+
+    <span class="k">new</span> <span class="nc">ALSModel</span><span 
class="o">(</span>
+      <span class="n">rank</span> <span class="k">=</span> <span 
class="n">m</span><span class="o">.</span><span class="n">rank</span><span 
class="o">,</span>
+      <span class="n">userFeatures</span> <span class="k">=</span> <span 
class="n">m</span><span class="o">.</span><span 
class="n">userFeatures</span><span class="o">,</span>
+      <span class="n">productFeatures</span> <span class="k">=</span> <span 
class="n">m</span><span class="o">.</span><span 
class="n">productFeatures</span><span class="o">,</span>
+      <span class="n">userStringIntMap</span> <span class="k">=</span> <span 
class="n">userStringIntMap</span><span class="o">,</span>
+      <span class="n">itemStringIntMap</span> <span class="k">=</span> <span 
class="n">itemStringIntMap</span><span class="o">)</span>
+  <span class="o">}</span>
+</pre></td></tr></tbody></table> </div> <h4 
id='working-with-spark-mllib&#39;s-als.train(....)' 
class='header-anchors'>Working with Spark MLlib&#39;s ALS.train(....)</h4><p>As 
mentioned above, MLlib&#39;s <code>Rating</code> does not support 
<code>String</code> user ID and item ID. Its <code>ALS.train</code> thus also 
assumes <code>Int</code>-only <code>Rating</code>.</p><p>Here you need to map 
your String-supported <code>Rating</code> to MLlib&#39;s Integer-only 
<code>Rating</code>. First, you can rename MLlib&#39;s Integer-only 
<code>Rating</code> to <code>MLlibRating</code> for clarity:</p><div 
class="highlight shell"><table style="border-spacing: 0"><tbody><tr><td 
class="gutter gl" style="text-align: right"><pre class="lineno">1</pre></td><td 
class="code"><pre>import org.apache.spark.mllib.recommendation.<span 
class="o">{</span>Rating <span class="o">=</span>&gt; MLlibRating<span 
class="o">}</span>
+</pre></td></tr></tbody></table> </div> <p>You then create a bi-directional 
map with <code>BiMap.stringInt</code> which maps each String record to an 
Integer index.</p><div class="highlight shell"><table style="border-spacing: 
0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre 
class="lineno">1
+2</pre></td><td class="code"><pre>val userStringIntMap <span 
class="o">=</span> BiMap.stringInt<span class="o">(</span>data.ratings.map<span 
class="o">(</span>_.user<span class="o">))</span>
+val itemStringIntMap <span class="o">=</span> BiMap.stringInt<span 
class="o">(</span>data.ratings.map<span class="o">(</span>_.item<span 
class="o">))</span>
+</pre></td></tr></tbody></table> </div> <p>Finally, you re-create each 
<code>Rating</code> event as <code>MLlibRating</code>:</p><div class="highlight 
shell"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" 
style="text-align: right"><pre class="lineno">1</pre></td><td 
class="code"><pre>MLlibRating<span class="o">(</span>userStringIntMap<span 
class="o">(</span>r.user<span class="o">)</span>, itemStringIntMap<span 
class="o">(</span>r.item<span class="o">)</span>, r.rating<span 
class="o">)</span>
+</pre></td></tr></tbody></table> </div> <p>In addition to 
<code>RDD[MLlibRating]</code>, <code>ALS.train</code> takes the following 
parameters: <em>rank</em>, <em>iterations</em>, <em>lambda</em> and 
<em>seed</em>.</p><p>The values of these parameters are specified in 
<em>algorithms</em> of 
MyRecommendation/<strong><em>engine.json</em></strong>:</p><div 
class="highlight shell"><table style="border-spacing: 0"><tbody><tr><td 
class="gutter gl" style="text-align: right"><pre class="lineno">1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15</pre></td><td class="code"><pre><span class="o">{</span>
+  ...
+  <span class="s2">"algorithms"</span>: <span class="o">[</span>
+    <span class="o">{</span>
+      <span class="s2">"name"</span>: <span class="s2">"als"</span>,
+      <span class="s2">"params"</span>: <span class="o">{</span>
+        <span class="s2">"rank"</span>: 10,
+        <span class="s2">"numIterations"</span>: 20,
+        <span class="s2">"lambda"</span>: 0.01,
+        <span class="s2">"seed"</span>: 3
+      <span class="o">}</span>
+    <span class="o">}</span>
+  <span class="o">]</span>
+  ...
+<span class="o">}</span>
+</pre></td></tr></tbody></table> </div> <p>PredictionIO will automatically 
loads these values into the constructor <code>ap</code>, which has a 
corresponding case class <code>ALSAlgorithmParams</code>:</p><div 
class="highlight scala"><table style="border-spacing: 0"><tbody><tr><td 
class="gutter gl" style="text-align: right"><pre class="lineno">1
+2
+3
+4
+5</pre></td><td class="code"><pre><span class="k">case</span> <span 
class="k">class</span> <span class="nc">ALSAlgorithmParams</span><span 
class="o">(</span>
+  <span class="n">rank</span><span class="k">:</span> <span 
class="kt">Int</span><span class="o">,</span>
+  <span class="n">numIterations</span><span class="k">:</span> <span 
class="kt">Int</span><span class="o">,</span>
+  <span class="n">lambda</span><span class="k">:</span> <span 
class="kt">Double</span><span class="o">,</span>
+  <span class="n">seed</span><span class="k">:</span> <span 
class="kt">Option</span><span class="o">[</span><span 
class="kt">Long</span><span class="o">])</span> <span class="k">extends</span> 
<span class="nc">Params</span>
+</pre></td></tr></tbody></table> </div> <p>The <code>seed</code> parameter is 
an optional parameter, which is used by MLlib ALS algorithm internally to 
generate random values. If the <code>seed</code> is not specified, current 
system time would be used and hence each train may produce different reuslts. 
Specify a fixed value for the <code>seed</code> if you want to have 
deterministic result (For example, when you are 
testing).</p><p><code>ALS.train</code> then returns a 
<code>MatrixFactorizationModel</code> model which contains RDD data. RDD is a 
distributed collection of items which <em>does not</em> persist. To store the 
model, you convert the model to <code>ALSModel</code> class at the end. 
<code>ALSModel</code> is a persistable class that extends 
<code>MatrixFactorizationModel</code>.</p> <blockquote> <p>The detailed 
implementation can be found at 
MyRecommendation/src/main/scala/<strong><em>ALSModel.scala</em></strong></p></blockquote>
 <p>PredictionIO will automatically store th
 e returned model, i.e. <code>ALSModel</code> in this case.</p><h3 
id='predict(...)' 
class='header-anchors'>predict(...)</h3><p><code>predict</code> is called when 
you send a JSON query to <a 
href="http://localhost:8000/queries.json";>http://localhost:8000/queries.json</a>.
 PredictionIO converts the query, such as <code>{ &quot;user&quot;: 
&quot;1&quot;, &quot;num&quot;: 4 }</code> to the <code>Query</code> class you 
defined previously.</p><p>The predictive model 
<code>MatrixFactorizationModel</code> of MLlib ALS, which is now extended as 
<code>ALSModel</code>, offers a method called <code>recommendProducts</code>. 
<code>recommendProducts</code> takes two parameters: user id (i.e. the 
<code>Int</code> index of <code>query.user</code>) and the number of items to 
be returned (i.e. <code>query.num</code>). It predicts the top <em>num</em> of 
items a user will like.</p><div class="highlight scala"><table 
style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: 
right">
 <pre class="lineno">1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15</pre></td><td class="code"><pre>  <span class="k">def</span> <span 
class="n">predict</span><span class="o">(</span><span 
class="n">model</span><span class="k">:</span> <span 
class="kt">ALSModel</span><span class="o">,</span> <span 
class="n">query</span><span class="k">:</span> <span 
class="kt">Query</span><span class="o">)</span><span class="k">:</span> <span 
class="kt">PredictedResult</span> <span class="o">=</span> <span 
class="o">{</span>
+    <span class="c1">// Convert String ID to Int index for Mllib
+</span>    <span class="n">model</span><span class="o">.</span><span 
class="n">userStringIntMap</span><span class="o">.</span><span 
class="n">get</span><span class="o">(</span><span class="n">query</span><span 
class="o">.</span><span class="n">user</span><span class="o">).</span><span 
class="n">map</span> <span class="o">{</span> <span class="n">userInt</span> 
<span class="k">=&gt;</span>
+      <span class="c1">// create inverse view of itemStringIntMap
+</span>      <span class="k">val</span> <span 
class="n">itemIntStringMap</span> <span class="k">=</span> <span 
class="n">model</span><span class="o">.</span><span 
class="n">itemStringIntMap</span><span class="o">.</span><span 
class="n">inverse</span>
+      <span class="c1">// recommendProducts() returns Array[MLlibRating], 
which uses item Int
+</span>      <span class="c1">// index. Convert it to String ID for returning 
PredictedResult
+</span>      <span class="k">val</span> <span class="n">itemScores</span> 
<span class="k">=</span> <span class="n">model</span><span 
class="o">.</span><span class="n">recommendProducts</span><span 
class="o">(</span><span class="n">userInt</span><span class="o">,</span> <span 
class="n">query</span><span class="o">.</span><span class="n">num</span><span 
class="o">)</span>
+        <span class="o">.</span><span class="n">map</span> <span 
class="o">(</span><span class="n">r</span> <span class="k">=&gt;</span> <span 
class="nc">ItemScore</span><span class="o">(</span><span 
class="n">itemIntStringMap</span><span class="o">(</span><span 
class="n">r</span><span class="o">.</span><span class="n">product</span><span 
class="o">),</span> <span class="n">r</span><span class="o">.</span><span 
class="n">rating</span><span class="o">))</span>
+      <span class="k">new</span> <span class="nc">PredictedResult</span><span 
class="o">(</span><span class="n">itemScores</span><span class="o">)</span>
+    <span class="o">}.</span><span class="n">getOrElse</span><span 
class="o">{</span>
+      <span class="n">logger</span><span class="o">.</span><span 
class="n">info</span><span class="o">(</span><span class="n">s</span><span 
class="s">"No prediction for unknown user ${query.user}."</span><span 
class="o">)</span>
+      <span class="k">new</span> <span class="nc">PredictedResult</span><span 
class="o">(</span><span class="nc">Array</span><span class="o">.</span><span 
class="n">empty</span><span class="o">)</span>
+    <span class="o">}</span>
+  <span class="o">}</span>
+</pre></td></tr></tbody></table> </div> <p>Note that 
<code>recommendProducts</code> returns the <code>Int</code> indices of items. 
You map them back to <code>String</code> with <code>itemIntStringMap</code> 
before they are returned.</p> <blockquote> <p>You have defined the class 
<code>PredictedResult</code> earlier.</p></blockquote> <p>PredictionIO passes 
the returned <code>PredictedResult</code> object to <em>Serving</em>.</p><h2 
id='serving' class='header-anchors'>Serving</h2><p>The <code>serve</code> 
method of class <code>Serving</code> processes predicted result. It is also 
responsible for combining multiple predicted results into one if you have more 
than one predictive model. <em>Serving</em> then returns the final predicted 
result. PredictionIO will convert it to a JSON response automatically.</p><p>In 
MyRecommendation/src/main/scala/<strong><em>Serving.scala</em></strong>,</p><div
 class="highlight scala"><table style="border-spacing: 0"><tbody><tr><td 
class="gutter gl" style
 ="text-align: right"><pre class="lineno">1
+2
+3
+4
+5
+6
+7
+8
+9</pre></td><td class="code"><pre><span class="k">class</span> <span 
class="nc">Serving</span>
+  <span class="k">extends</span> <span class="nc">LServing</span><span 
class="o">[</span><span class="kt">Query</span>, <span 
class="kt">PredictedResult</span><span class="o">]</span> <span 
class="o">{</span>
+
+  <span class="k">override</span>
+  <span class="k">def</span> <span class="n">serve</span><span 
class="o">(</span><span class="n">query</span><span class="k">:</span> <span 
class="kt">Query</span><span class="o">,</span>
+    <span class="n">predictedResults</span><span class="k">:</span> <span 
class="kt">Seq</span><span class="o">[</span><span 
class="kt">PredictedResult</span><span class="o">])</span><span 
class="k">:</span> <span class="kt">PredictedResult</span> <span 
class="o">=</span> <span class="o">{</span>
+    <span class="n">predictedResults</span><span class="o">.</span><span 
class="n">head</span>
+  <span class="o">}</span>
+<span class="o">}</span>
+</pre></td></tr></tbody></table> </div> <p>When you send a JSON query to <a 
href="http://localhost:8000/queries.json";>http://localhost:8000/queries.json</a>,
 <code>PredictedResult</code> from all models will be passed to 
<code>serve</code> as a sequence, i.e. <code>Seq[PredictedResult]</code>.</p> 
<blockquote> <p>An engine can train multiple models if you specify more than 
one Algorithm component in <code>object RecommendationEngine</code> inside 
<strong><em>Engine.scala</em></strong>. Since only one 
<code>ALSAlgorithm</code> is implemented by default, this <code>Seq</code> 
contains one element.</p></blockquote> <p>Now you should have a good 
understanding of the DASE model. We will show you an example of customizing the 
Data Preparator to exclude certain items from your training set.</p><h4 
id='<a-href="/templates/recommendation/reading-custom-events/">next:-reading-custom-events</a>'
 class='header-anchors' ><a 
href="/templates/recommendation/reading-custom-events/">Next: Reading Cu
 stom Events</a></h4></div></div></div></div><footer><div 
class="container"><div class="seperator"></div><div class="row"><div 
class="col-md-6 col-xs-6 footer-link-column"><div 
class="footer-link-column-row"><h4>Community</h4><ul><li><a 
href="//docs.prediction.io/install/" target="blank">Download</a></li><li><a 
href="//docs.prediction.io/" target="blank">Docs</a></li><li><a 
href="//github.com/apache/incubator-predictionio" 
target="blank">GitHub</a></li><li><a 
href="mailto:[email protected]"; 
target="blank">Subscribe to User Mailing List</a></li><li><a 
href="//stackoverflow.com/questions/tagged/predictionio" 
target="blank">Stackoverflow</a></li></ul></div></div><div class="col-md-6 
col-xs-6 footer-link-column"><div 
class="footer-link-column-row"><h4>Contribute</h4><ul><li><a 
href="//predictionio.incubator.apache.org/community/contribute-code/" 
target="blank">Contribute</a></li><li><a 
href="//github.com/apache/incubator-predictionio" target="blank">Source 
 Code</a></li><li><a href="//issues.apache.org/jira/browse/PIO" 
target="blank">Bug Tracker</a></li><li><a 
href="mailto:[email protected]"; 
target="blank">Subscribe to Development Mailing 
List</a></li></ul></div></div></div></div><div id="footer-bottom"><div 
class="container"><div class="row"><div class="col-md-12"><div 
id="footer-logo-wrapper"><img alt="PredictionIO" 
src="/images/logos/logo-white-d1e9c6e6.png"/></div><div 
id="social-icons-wrapper"><a class="github-button" 
href="https://github.com/apache/incubator-predictionio"; data-style="mega" 
data-count-href="/apache/incubator-predictionio/stargazers" 
data-count-api="/repos/apache/incubator-predictionio#stargazers_count" 
data-count-aria-label="# stargazers on GitHub" aria-label="Star 
apache/incubator-predictionio on GitHub">Star</a> <a class="github-button" 
href="https://github.com/apache/incubator-predictionio/fork"; 
data-icon="octicon-git-branch" data-style="mega" 
data-count-href="/apache/incubator-pre
 dictionio/network" 
data-count-api="/repos/apache/incubator-predictionio#forks_count" 
data-count-aria-label="# forks on GitHub" aria-label="Fork 
apache/incubator-predictionio on GitHub">Fork</a> <script id="github-bjs" 
async="" defer="" src="https://buttons.github.io/buttons.js";></script><a 
href="//www.facebook.com/predictionio" target="blank"><img alt="PredictionIO on 
Twitter" src="/images/icons/twitter-ea9dc152.png"/></a> <a 
href="//twitter.com/predictionio" target="blank"><img alt="PredictionIO on 
Facebook" src="/images/icons/facebook-5c57939c.png"/></a> 
</div></div></div></div></div></footer></div><script>(function(w,d,t,u,n,s,e){w['SwiftypeObject']=n;w[n]=w[n]||function(){
+(w[n].q=w[n].q||[]).push(arguments);};s=d.createElement(t);
+e=d.getElementsByTagName(t)[0];s.async=1;s.src=u;e.parentNode.insertBefore(s,e);
+})(window,document,'script','//s.swiftypecdn.com/install/v1/st.js','_st');
+
+_st('install','HaUfpXXV87xoB_zzCQ45');</script><script 
src="/javascripts/application-280db181.js"></script></body></html>
\ No newline at end of file

Reply via email to