<?xml version="1.0"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Thesis by @mljungblad</title>
    <link>http://thesis.ljungblad.nu/</link>
    <atom:link href="http://thesis.ljungblad.nu/feed.xml" rel="self" type="application/rss+xml" />
    <description>Documenting my way to a master thesis on building recommender systems</description>
    <language>en-us</language>
    <pubDate>Wed, 23 May 2012 04:57:14 -0700</pubDate>
    <lastBuildDate>Wed, 23 May 2012 04:57:14 -0700</lastBuildDate>

    
    <item>
      <title>The value of instrumentation</title>
      <link>http://thesis.ljungblad.nu/2012/05/23/the_value_of_instrumentation</link>
      <pubDate>Wed, 23 May 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/05/23/the_value_of_instrumentation</guid>
      <description>&lt;p&gt;As I&amp;#8217;m continuing to take measurements on the recommendation engine&amp;#8217;s performance I&amp;#8217;m becoming increasingly aware of the value of instrumentation. Several noteworthy bloggers and companies repeatedly talk about it. The mantra follows something along the lines &amp;#8220;if you don&amp;#8217;t instrument, you have no clue what is happening.&amp;#8221; It couldn&amp;#8217;t be more true.&lt;/p&gt;
&lt;p&gt;Being a project that has mostly been confined to my development machine and small-scale tests, there hasn&amp;#8217;t been a strong need for looking inside. Various log.debug() messages coupled with some grep/awk magic have so far been sufficient.&lt;/p&gt;
&lt;p&gt;At the time of writing a 5-minute performance test is running. During this time I have essentially no insight into what the system is up to. Only when I get the results back and can plot the graphs will I know how it performed. Considering that I do not trust the software that I&amp;#8217;ve written (I wouldn&amp;#8217;t do that till I see it run for a substantial amount of time) it seems it would have been a good time investment to set up better run-time metrics.&lt;/p&gt;
&lt;p&gt;Developed by the guys behind &lt;a href=&quot;https://www.yammer.com/&quot;&gt;Yammer&lt;/a&gt;, I found &lt;a href=&quot;http://metrics.codahale.com/&quot;&gt;Metrics&lt;/a&gt; &amp;#8211; a Java library to easily extract information from deployed code. It can export the information to both &lt;a href=&quot;http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html&quot;&gt;jconsole&lt;/a&gt; (handy tool to see what&amp;#8217;s happening inside your &lt;span class=&quot;caps&quot;&gt;JVM&lt;/span&gt;), as well as the more large-scale tools &lt;a href=&quot;http://graphite.wikidot.com/&quot;&gt;Graphite&lt;/a&gt; and &lt;a href=&quot;http://ganglia.sourceforge.net/&quot;&gt;Ganglia&lt;/a&gt;. It looks promising for code running in production (which it was designed for), but perhaps not the most optimal tool for development/performance testing.&lt;/p&gt;
&lt;p&gt;At the moment I don&amp;#8217;t have the time to explore Metrics further, but will definitely put it in my toolbox.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Progress!</title>
      <link>http://thesis.ljungblad.nu/2012/05/23/progress</link>
      <pubDate>Wed, 23 May 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/05/23/progress</guid>
      <description>&lt;p&gt;Compared to last week&amp;#8217;s miserable results. Today it is looking a lot better.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bad&lt;/strong&gt;&lt;br /&gt;
&lt;img src=&quot;/images/depressing_results.png&quot; title=&quot;Bad results&quot; alt=&quot;Bad results&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better&lt;/strong&gt;&lt;br /&gt;
&lt;img src=&quot;/images/throughput_good.png&quot; title=&quot;Better results&quot; alt=&quot;Better results&quot; /&gt;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>When all else fail</title>
      <link>http://thesis.ljungblad.nu/2012/05/15/when_all_else_fails</link>
      <pubDate>Tue, 15 May 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/05/15/when_all_else_fails</guid>
      <description>&lt;p&gt;So, first ever results from the recommendation engine running on &lt;em&gt;five&lt;/em&gt; machines.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/depressing_results.png&quot; title=&quot;Not really what I expected...&quot; alt=&quot;Not really what I expected...&quot; /&gt;&lt;/p&gt;
&lt;p&gt;What now? The graph above suggests that there are more failures than successfully answered requests. Not what I had in mind. Moreover, the it fails already around 90-100 requests/second, and there are even failures at a higher rate. Looking at another graph (not posted) the response times are around 1 second which is probably causing the high number of failures as the hard timeouts are configured to 1 second.&lt;/p&gt;
&lt;p&gt;What is the cause? There may be several reasons of course. The mistake I&amp;#8217;ve made is to run ahead of myself, I think. Here are a few reasons as to why the results may be quite depressing compared to those taken earlier.&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;I decoupled the http-interface to a separate java-application (running in a separate &lt;span class=&quot;caps&quot;&gt;JVM&lt;/span&gt;). I didn&amp;#8217;t want the &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; interface to interfere with the Akka system containing the recommendation engine.&lt;/li&gt;
	&lt;li&gt;Previously I have only tested the performance with static &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; requests. This means every request is identical and is routed to the same itemset. In the run above each request is randomly generated. In order to solve this I decided to implement my own &lt;a href=&quot;http://ilkinbalkanay.blogspot.com.es/2010/03/load-test-whatever-you-want-with-apache.html&quot;&gt;Jmeter Sampler&lt;/a&gt;. This was a simple exercise, but I&amp;#8217;m not sure how much my implementation affects the timing results measured by Jmeter. Maybe I&amp;#8217;m doing something wrong?&lt;/li&gt;
	&lt;li&gt;All requests are issued over the network. All machines, however, sit in the same rack and the normal round-trip time is about half a millisecond.&lt;/li&gt;
	&lt;li&gt;There is a design flaw with the &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; interface. As I was writing on the report yesterday I got the feeling that the &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; server doesn&amp;#8217;t handle requests concurrently. I.e when the request is accepted and forwarded to the native interface it is blocking before it returns a result and processes the next message. It is more likely, to be honest, that this error is in the native interface that I&amp;#8217;ve created though than the &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; library.&lt;/li&gt;
	&lt;li&gt;The design of sharing the workload between the nodes does not work. There is a bottleneck elsewhere that I&amp;#8217;m missing. Potential suspects are the native-interface, routing and the workers. Routing is a sequential part of the code base that I&amp;#8217;m aware can cause troubles during high workloads, but I didn&amp;#8217;t expect it to peak already at ~100 requests/second according to previous measurements.&lt;/li&gt;
	&lt;li&gt;I&amp;#8217;m missing something else.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Next step will be to try with a smaller set-up (1 node, 1 test machine) locally and see if I get similar results. If not, I&amp;#8217;ll try to profile the time spent in the different parts of the application to see where that may lead.&lt;/p&gt;
&lt;p&gt;When all else fails&amp;#8230;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Unix tools</title>
      <link>http://thesis.ljungblad.nu/2012/05/15/unix_tools</link>
      <pubDate>Tue, 15 May 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/05/15/unix_tools</guid>
      <description>&lt;p&gt;I&amp;#8217;m often impressed by the pletheora of tools available in *nix environments. It&amp;#8217;s incredible how these small and composable applications have evolved and is creating an amazing ecosystem. The &amp;#8220;do one thing and do it really well&amp;#8221; truly drives their design.&lt;/p&gt;
&lt;p&gt;There are three tools, two of which are default in any *nix environment and one which follows similar principles: &lt;code&gt;mktemp&lt;/code&gt;, &lt;code&gt;nohup&lt;/code&gt; and &lt;code&gt;dtach&lt;/code&gt;, that I&amp;#8217;ve used to deploy the recommendation engine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;nohup&lt;/strong&gt; enables you to start other applications that does not listen to the &lt;span class=&quot;caps&quot;&gt;SIGHUP&lt;/span&gt; signal. The &lt;span class=&quot;caps&quot;&gt;SIGHUP&lt;/span&gt; signal is sent to all processes that are spawned by a terminal. For example, if I log in using &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; to a remote machine and start an application, it will automatically recieve a &lt;span class=&quot;caps&quot;&gt;SIGHUP&lt;/span&gt; when I logout from the &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; session. Nifty, but not always desirable. &lt;code&gt;nohup&lt;/code&gt;, hence, solves this issue by disabling the the listener.&lt;/p&gt;
&lt;pre&gt;nohup java -jar recsys.jar app.conf &amp;gt; /tmp/recsys.log 2&amp;gt;&amp;amp;1 &amp;amp; echo $! &amp;gt; recsys.pid&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;mktemp&lt;/strong&gt; does exactly what it says, it makes temporary files. &lt;code&gt;mktemp -n /tmp/recsys.XXXX&lt;/code&gt; can for example be used to create a log file that I can pipe output to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;dtach&lt;/strong&gt; is not bundled with the OS per se but I found it to be a pretty handy complement to its more heavy-weight big brother &lt;code&gt;screen&lt;/code&gt;. Using &lt;code&gt;dtach -c /tmp/app.session app&lt;/code&gt; you start an application in a separate terminal session. With &lt;code&gt;-c&lt;/code&gt; you are not attached to it by default. If you want to attach to it, simply issue &lt;code&gt;dtach -a /tmp/app.session&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;*nix is a great example of good software design.&lt;/p&gt;
&lt;p&gt;&amp;lt;3&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Weaving the fabric</title>
      <link>http://thesis.ljungblad.nu/2012/05/12/weaving_the_fabric</link>
      <pubDate>Sat, 12 May 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/05/12/weaving_the_fabric</guid>
      <description>&lt;p&gt;After the last days dispair fighting with packaging jar files and configuration management in order to deploy the system on a set of servers, I&amp;#8217;ve yesterday worked with something delightful: Fabric.&lt;/p&gt;
&lt;p&gt;I posed this question to a hacker-friend of mine: what is the easiest way to deploy and run a set of configuration commands on five machines. The only requirement? It shouldn&amp;#8217;t take me forever to set-up.&lt;/p&gt;
&lt;p&gt;He immediately posted a snippet of python code using the Fabric library.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://docs.fabfile.org/en/1.4.2/index.html#usage-documentation&quot;&gt;Fabric&lt;/a&gt; is a &amp;#8220;tool for streamlining the use of &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; for application deployment or systems administration tasks&amp;#8221;. And what&amp;#8217;s more, it&amp;#8217;s super-easy to use and has good documentation!&lt;/p&gt;
&lt;p&gt;By defining small tasks, which are composeable, you declare commands to run on remote machines. You can execute commands locally too. With three commands and a few tasks I had the whole procedure set-up: Packaging jar files, moving them to one of the remote servers, distributing them from there to the others (our upload capacity is kind of slow), uploading the test data, generating a configuration template, uploading this one, generating host-specific configurations based on the template, and finally (re)starting the application.&lt;/p&gt;
&lt;p&gt;Generating and uploading configuration files look like this:&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2658496.js&quot;&gt; &lt;/script&gt;&lt;/p&gt;
&lt;p&gt;And can be run by issuing &lt;code&gt;fab prepare_config:data=sample,maxcap=20 config&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Happy deploying!&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Configuration management</title>
      <link>http://thesis.ljungblad.nu/2012/05/08/configuration_management</link>
      <pubDate>Tue, 08 May 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/05/08/configuration_management</guid>
      <description>&lt;p&gt;One thing that I find notoriously hard to get right in every project I&amp;#8217;m working on is &lt;em&gt;configuration management&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It sucks.&lt;/p&gt;
&lt;p&gt;There are always a pletheora of libraries, tools and techniques claiming to have tamed the unicorn. To make matters worse everyone uses different notations, different instantiation methods, and different access methods.&lt;/p&gt;
&lt;p&gt;For a while I thought Scala+Akka had found the holy grail: &lt;a href=&quot;https://github.com/typesafehub/config&quot;&gt;ConfigFactory&lt;/a&gt;. Now I&amp;#8217;m not all that convinced after having struggled with for a while. It&amp;#8217;s probably two reasons at play: first, documentation is rusty at best making it hard to interpret what the load() function really does (I ended up looking at the source code to find out it didn&amp;#8217;t do at all what I expected it to do). Secondly, I&amp;#8217;m probably doing something wrong, especially with respect to getting the design right.&lt;/p&gt;
&lt;p&gt;Configuration libraries worthy their names have at least the majority of the following properties:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;use a big-name markup language for describing the config file (json, yaml, or possibly xml although it is usually bloated)&lt;/li&gt;
	&lt;li&gt;support tree-like organisation of configuration properties&lt;/li&gt;
	&lt;li&gt;once instantiated in your application be globally accessible (singletons are bad but configurations are application-cutting)&lt;/li&gt;
	&lt;li&gt;be composable to multiple files if needed&lt;/li&gt;
	&lt;li&gt;support the overriding of settings using for example system environment or vm variables&lt;/li&gt;
	&lt;li&gt;be instantiated once and only once in runtime, meaning the settings once instantiated are immutable (runtime variation is a whole other matter (I wrote a thesis on it))&lt;/li&gt;
	&lt;li&gt;be mockable/replaceable for test environments&lt;/li&gt;
	&lt;li&gt;provides a small and intuitive api&lt;/li&gt;
	&lt;li&gt;preferably come with decent documentation and sample implementations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ConfigFactory by Typesafe actually fulfills most of above out of the box.&lt;/p&gt;
&lt;p&gt;The world doesn&amp;#8217;t need yet another configuration library, so don&amp;#8217;t expect me to start hacking on one. Perhaps I&amp;#8217;ll fork ConfigFactory one day and fix its broken parts, for now I&amp;#8217;ve hacked my way around its major shortcoming (globally accessible settings).&lt;/p&gt;
&lt;p&gt;Your mileage may vary&amp;#8230;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;/rant&amp;gt;&lt;/code&gt;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Balancing the cluster</title>
      <link>http://thesis.ljungblad.nu/2012/05/04/node_join</link>
      <pubDate>Fri, 04 May 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/05/04/node_join</guid>
      <description>&lt;p&gt;Yesterday I explained briefly what happens when the recommendation cluster is bootstrapped. Today I thought I would go into a little bit more detail, explaining how a new node figures out what to prioritise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First node to join&lt;/strong&gt; is obviously on its own. I assume that a Zookeeper-like service is available to keep track of members of the cluster. In my current setup this is a dummy nameserver of 10 lines of scala+akka code which fulfills the purpose just fine for testing. This service must be running before any node can potentially join the cluster.&lt;/p&gt;
&lt;p&gt;The first thing the node does is to register with the nameserver. The nameserver will reply by sending all the currently registered nodes, including the node issuing the request. If there are no other nodes in the cluster it will become responsible for coordinating the bootstrapping procedure of the cluster. This responsibility includes two things:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Read the file with itemsets&amp;#8217;s signatures and assign internal id&amp;#8217;s to each. This id is only used internally by the recommendation cluster.&lt;/li&gt;
	&lt;li&gt;Load as many itemsets to memory as the node can handle (1 itemset = 1 worker) &amp;#8211; this can either be manually restricted or determined from within the system. It is manual for now since that makes it more predictable and easier to evaluate.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Assuming that the first node is not able to maintain all itemsets in memory on its own it will mark those that are not yet loaded and should be given priority.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;As the second node joins&lt;/strong&gt; the it will, similarly to the first node, register with the nameserver and receive a list of existing nodes. When discovering that existing nodes exists it will:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Replicate the first node&amp;#8217;s registry to learn what itemsets are already loaded and where the workers to serve those itemsets are residing. If it receives registers from more than one node the registers are merged. This way they will eventually be consistent on all nodes.&lt;/li&gt;
	&lt;li&gt;Retrieve a list of itemsets to load. Once all nodes have replied it will sort the itemsets according to following formula: itemsets not previously loaded will be prioritised first. If all itemsets are loaded it will sort the itemsets according to their popularity (determined by the number of requests each itemset retrieves).&lt;/li&gt;
	&lt;li&gt;Load the prioritised itemsets. One worker per itemset is started and it will ensure to register with both the local node on which it resides, as well as on the other nodes in the cluster.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;A cluster with a lot of direct links&lt;/strong&gt; will be expensive to maintain. Well, there are both sides to the argument. Maintaining more links have to be put in perspective to the frequency of expected failures and the cost of fixing/updating the link once a node recovers. I plan to evaluate this more closely in the next few days. An alternative is to add another level of indirection by storing only at which node the worker belongs. I would expect a small (max 5) nodes with a few hundred itemsets each to be sufficient for most cases. Maintaining the links for such a setup may cause a certain spike (increased latency) when a node dies, but overall be manageable since they otherwise rarely change. The time spent routing is possibly capped by the similarity function anyway. If this proves to be a bottleneck there&amp;#8217;s need for more efficient datastructures and some further parallelisation. Actually, when I think about it, there is a lot which can be improved. First get it running&amp;#8230;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Failure scenarios&lt;/strong&gt; are plenty. That said, there are some resiliance to node and/or worker failures.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;The nodes establishes monitors for the workers, such that if one dies, it will be removed from the registry. When the worker is restarted by the worker&amp;#8217;s supervisor it automatically re-registers with all nodes.&lt;/li&gt;
	&lt;li&gt;If a node dies, the same procedure as above happens except that there is nothing to restart the node.&lt;/li&gt;
	&lt;li&gt;Nodes can obviously fail during start-up. The case when the first node joining the cluster fails (before all itemsets are loaded at some node) is, however, not handled.&lt;/li&gt;
	&lt;li&gt;A node which fails and rejoins continuously could probably overload the system. There is no protection against thrashing, such as throttling the number of join requests.&lt;/li&gt;
	&lt;li&gt;If all available replicas for a particular itemset is down it is needed to respawn them from persistent storage (local file system or wherever they are stored). This is still unresolved and deserves a post on its own.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now it remains to see if this scales sufficiently and what the impact of node join and leave is, and to rewrite this text more formally so that I can use it in the report.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Towards distributed evaluation</title>
      <link>http://thesis.ljungblad.nu/2012/05/03/towards_distributed_evaluation</link>
      <pubDate>Thu, 03 May 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/05/03/towards_distributed_evaluation</guid>
      <description>&lt;p&gt;Today is big progress day. One of the things that I&amp;#8217;ve set out to evaluate is the scalability of the system. Specifically I want to investigate two things:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;how the system behaves as the quantity of data increases, and&lt;/li&gt;
	&lt;li&gt;the throughput and latency of requests that it supports&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Before I had used the &lt;a href=&quot;http://doc.akka.io/docs/akka/2.0/dev/multi-jvm-testing.html&quot;&gt;MultiJVM plugin&lt;/a&gt; for Akka to test with multiple JVMs locally. Today I&amp;#8217;ve refactored the code and enabled it to run from a scriptable number of machines.&lt;/p&gt;
&lt;p&gt;When a node starts it registers with a nameserver, as a confirmation on its registration it is sent a list with all other nodes that are also registered. From here on there are two different paths. If the node is first to join the cluster it will become responsible for populating the cluster with data. Hence, once the second node joins it will before alleviating load from the first node, ask if there is data that still hasn&amp;#8217;t been loaded and prioritise that. The number of data itemsets a node can load depends on its memory capacity. If there are no new data itemsets to load when a node joins it will automatically alleviate load from the existing nodes. Any node can thereafter serve incoming recommendation requests.&lt;/p&gt;
&lt;p&gt;Pretty cool.&lt;/p&gt;
&lt;p&gt;Now I need to sort out two bugs that I&amp;#8217;ve not been able to catch with the much smaller test cases that I had with the local setting. Afterwards I have to identify all failure-cases that I handle and those that I do not.&lt;/p&gt;
&lt;pre&gt;
&amp;gt; run 127.0.0.1 2552 127.0.0.1:2550
[info] Running recsys.Main 127.0.0.1 2552 127.0.0.1:2550
Using configuration: 
[
 address: 127.0.0.1:2552
 path: /Users/marcus/tensor/
 filename: data.out
 replicas: 1
 nameserver: 127.0.0.1:2550
 nodemaxcapacity: 5
]
[INFO] [05/03/2012 18:03:03.149] [run-main] [ActorSystem(recsys)] 
	REMOTE: RemoteServerStarted@akka://recsys@127.0.0.1:2552
[INFO] [05/03/2012 18:03:03.251] [run-main] [ActorSystem(recsys)] 
	REMOTE: RemoteClientStarted@akka://nameserver@127.0.0.1:2550
Bootstrapping recsys cluster.
New id: 0 worker: Actor[akka://recsys/user/$a]
New id: 1 worker: Actor[akka://recsys/user/$b]
New id: 2 worker: Actor[akka://recsys/user/$c]
New id: 3 worker: Actor[akka://recsys/user/$d]
New id: 4 worker: Actor[akka://recsys/user/$e]
Recsys running. Press 'return' key to exit.
&lt;/pre&gt;</description>
    </item>
    
    <item>
      <title>Illustrating matrix factorisation</title>
      <link>http://thesis.ljungblad.nu/2012/05/02/illustrating_matrix_factorisation</link>
      <pubDate>Wed, 02 May 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/05/02/illustrating_matrix_factorisation</guid>
      <description>&lt;p&gt;As part of the report I&amp;#8217;m including a section on the intuition behind matrix factorisation. Since I&amp;#8217;m not the biggest fan of maths (it&amp;#8217;s fascinating when it works but basically I suck at it) I want a more illustrative example. Prefering code over mathematical equations I decided to include some pseudo-code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/als_pseudo.png&quot; title=&quot;Alternating Least Squares pseudo-code&quot; alt=&quot;Alternating Least Squares pseudo-code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;However, I&amp;#8217;m not every happy with it. Too many abbreviations and complicated syntax. Nick suggested making fluffy functions out of the &lt;code&gt;upm[u,:]&lt;/code&gt; parts since they literally translate to &amp;#8220;u&amp;#8217;th row of matrix upm&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Alternatively I could just stick to the original python code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/als_python.png&quot; title=&quot;Alternating Least Squares python code&quot; alt=&quot;Alternating Least Squares python code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Hopefully with the examples I&amp;#8217;ve provided it should be roughly understandable what one can achieve with matrix factorisation: approximating unknown values.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Planning evaluation</title>
      <link>http://thesis.ljungblad.nu/2012/04/30/planning_evaluation</link>
      <pubDate>Mon, 30 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/30/planning_evaluation</guid>
      <description>&lt;p&gt;According to my initial plan I want to start doing the evaluation in May. This means that a majority of the code will be frozen soon too. I&amp;#8217;m almost on track with that plan, but there are some areas of the code which are still subject to change.&lt;/p&gt;
&lt;p&gt;Nevertheless, I&amp;#8217;ve started to outline what I want to measure and tried to indicate its difficulty and usefullness. They are subject to change.&lt;/p&gt;
&lt;p&gt;&lt;iframe width='580' height='550' frameborder='0' src='https://docs.google.com/spreadsheet/pub?key=0AlCmHxEFYtFedHNwcVJ6SEVYdVEwUU54WTdmX1hGMHc&amp;output=html&amp;widget=true'&gt;&lt;/iframe&gt;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>More on Evaluation</title>
      <link>http://thesis.ljungblad.nu/2012/04/26/more_on_evaluation</link>
      <pubDate>Thu, 26 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/26/more_on_evaluation</guid>
      <description>&lt;p&gt;Guy Shani and Asela Gunawardana contributed a chapter on evaluating recommendation systems to the heavy book: The Recommender Systems Handbook. A book which litterally covers everything, with the possible exception of papers covering the architecting recommender systems for scale.&lt;/p&gt;
&lt;p&gt;Shani&amp;#8217;s chapter did not add much new information than that given by Herlocker et al. They add upon it, of course, especially with respect to measuring confidence, and they dig further into user studies. But overall I think there was nothing of particular interest. Probably I don&amp;#8217;t have sufficient background knowledge to appreciate it. However, they did include a section on scalability which I thought was relevant.&lt;/p&gt;
&lt;p&gt;For anyone with a system&amp;#8217;s background it isn&amp;#8217;t news (but I suspect it may have been for some of the algorithm lovers). Essentially, they suggest to measure:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;complexity of the algorithm (including annotations whether it is cpu or memory bound)&lt;/li&gt;
	&lt;li&gt;behaviour as number of users and/or number of items grow&lt;/li&gt;
	&lt;li&gt;time to compute a recommendation (more commonly known as throughput and latency)&lt;/li&gt;
	&lt;li&gt;coverage, meaning how many of the items can be recommended within a given timeframe&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I need to decide which and how to do it and get going.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to evaluate a recommendation system?</title>
      <link>http://thesis.ljungblad.nu/2012/04/24/background_on_evaluation</link>
      <pubDate>Tue, 24 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/24/background_on_evaluation</guid>
      <description>&lt;p&gt;As I&amp;#8217;m starting to look into the evaluation of the system I was curious to find related work in this area. Linas suggested two papers which form the backbone of recommender system evaluation. Both of them are written by well-known researchers within the field.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Herlocker, Jonathan L., Joseph A. Konstan, Loren G. Terveen, John, and T. Riedl. &lt;a href=&quot;http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.78.8384&quot;&gt;Evaluating Collaborative Filtering Recommender Systems.&lt;/a&gt; &lt;span class=&quot;caps&quot;&gt;ACM&lt;/span&gt; Transactions on Information Systems 22 (2004): 5–53.&lt;/li&gt;
	&lt;li&gt;Ricci, Francesco, Lior Rokach, and Paul B. Kantor. Recommender Systems Handbook. Springer, 2010.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#8217;ve began reading the &amp;#8220;old&amp;#8221; one by Herlocker et al to get an understanding of the basics. Here&amp;#8217;s what I&amp;#8217;ve found so far.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Evaluating recommendation systems and algorithms is difficult. It depends heavily on the data, its size and its properties. It is also difficult because the goals of evaluation differs. For example, some want to measure accuracy and some may be more marketing related (click-through). In the end it is user-satisfaction that counts.&lt;/li&gt;
	&lt;li&gt;Begin with defining the end-user&amp;#8217;s goals and tasks. This should be the first point for any evaluation. For example, does the user simply want to &lt;em&gt;browse around&lt;/em&gt; or are they strictly interested in &lt;em&gt;finding good items&lt;/em&gt;?&lt;/li&gt;
	&lt;li&gt;Define the user, define the environment it operates in, and define the data.&lt;/li&gt;
	&lt;li&gt;Data has different properties:
	&lt;ul&gt;
		&lt;li&gt;Is novelty prefered over accuracy? Items recommended may be highly relevant (i.e liked by the user) but already known. One may also consider the cost vs benefit of the recommendation. How computationally expensive is it to generate compared to the benefit or the click-through generated?&lt;/li&gt;
		&lt;li&gt;Are the ratings implicit or explict? What other inherent features may exist, such as demographics or time?&lt;/li&gt;
		&lt;li&gt;Finally, what does the data itself look like? Sparse? Dense? Size and distribution. These are all important to consider when comparing algorithms between each other. Some algorithms are more suited to implicit ratings, but the same algorithm may perform horribly on data with explicit ratings.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;There are a number of commonly used measures in previous litterature. The most relevant for me, taking data into consideration, may be:
	&lt;ul&gt;
		&lt;li&gt;Precision and Recall &amp;#8211; normally these are measured together as they inversely affect one another. If Precision is higher, recall is lower, and the opposite.&lt;/li&gt;
		&lt;li&gt;Mean Average Precision &amp;#8211; is the average precision over several queries.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;They make a good point about accuracy not being all there is to recommendations. A more appropriate measure may be usefulness but that is a lot harder to evaluate. By including a measure (percentage) of the dataset that the recommendation system can provide predictions for&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, a measure for how fast an algorithm can produce recommendations, and a novelty measure, we can start to evaluate the usefulness aspect.
	&lt;ul&gt;
		&lt;li&gt;An interesting version of coverage is &amp;#8220;What percentage of available items does this recommender ever recommend to users?&amp;#8221; This is related to my current experimental results on only few clusters being used to make recommendations.&lt;/li&gt;
		&lt;li&gt;Learning rate is more closely related to the offline model in my case.&lt;/li&gt;
		&lt;li&gt;What strikes me about the novelty metrics proposed is how subjective they are. In fact, all recommendations are highly subjective and we&amp;#8217;re trying to quantitise them.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;First rule of recommender systems in e-commerce: &amp;#8220;Don&amp;#8217;t make me look stupid!&amp;#8221;&lt;/li&gt;
	&lt;li&gt;Eventually there has to be user evaluation. It may take many forms and is a field in its own right. However, it should at the very least focus on the defined goals and tasks that a user perform.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; This is particularly interesting as one of the design goals for my thesis has been to be able to recommend from a large set of items, without stripping out for example old items. But with a large item catalogue it becomes impossible within the given time constraints to provide predictions for all items.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Follow your guts</title>
      <link>http://thesis.ljungblad.nu/2012/04/23/follow_your_guts</link>
      <pubDate>Mon, 23 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/23/follow_your_guts</guid>
      <description>&lt;p&gt;This weekend I decided to dedicate &lt;strong&gt;four&lt;/strong&gt; hours to an experimental upgrade from Akka 1.3 to Akka 2.0 of my thesis-system. There were a number of features in &lt;a href=&quot;http://akka.io&quot;&gt;Akka 2.0&lt;/a&gt; that had attracted my attention and I was facing challenges with it in 1.3.&lt;/p&gt;
&lt;p&gt;Several talented people, including my supervisor, rightly advised against such a move so late into the work. &lt;a href=&quot;http://lalith.in&quot;&gt;Lalith&lt;/a&gt; pointed out that you can get away with your PhD on relatively old pieces of code. And true, a thesis probably shouldn&amp;#8217;t be tied to a particular version of your code, but rather to the theories that it explores. Nevertheless, I felt hunger to tinker was too great to control. To not completely go over board, I restricted my time for the upgrade to four hours so as to not endlessly continue along the lines &amp;quot;just this small change to and then I&amp;#8217;m do&amp;#8230; &amp;quot; Right.&lt;/p&gt;
&lt;p&gt;Overall it was fairly successful. It took me four hours and 15 minutes to complete the transition. The pain of upgrading comes from the fact that Akka 2.0 isn&amp;#8217;t backwards compatible. APIs have changed, though reasonably well-motivated by the team behind it, it certainly isn&amp;#8217;t a straightforward change for projects with much larger code-bases than mine (core is less than 600 scala lines excluding tests).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wins:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Remoting became a lot simpler. I&amp;#8217;m now able to run recommendations across several nodes.&lt;/li&gt;
	&lt;li&gt;Code readability improved with respect to actor creation&lt;/li&gt;
	&lt;li&gt;Less code (not really due to Akka 2.0, but in the process I got rid of some stuff that wasn&amp;#8217;t used)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Losses:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;I no longer have a &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;-interface as the http-library I used isn&amp;#8217;t 2.0 compatible yet. Alternatives exists but I haven&amp;#8217;t explored this option. For now a command-line interface suffices.&lt;/li&gt;
	&lt;li&gt;The bugs I haven&amp;#8217;t found yet due to the upgrade&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the end I will follow my supervisor&amp;#8217;s dangerous advice:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For once (do not abuse this advice), listen to your guts. ;-)&lt;/p&gt;
&lt;/blockquote&gt;</description>
    </item>
    
    <item>
      <title>Towards real-world testing</title>
      <link>http://thesis.ljungblad.nu/2012/04/19/testing_with_real_data</link>
      <pubDate>Thu, 19 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/19/testing_with_real_data</guid>
      <description>&lt;p&gt;Up until now I&amp;#8217;ve mostly used fictitious examples to test the recommender system that&amp;#8217;s being developed. This data was generated with random numbers without any correlation whatsoever to real world events. Today, however, that changed.&lt;/p&gt;
&lt;p&gt;One of the advantages of doing a thesis with a social network is that I can test with &lt;em&gt;real data&lt;/em&gt;. This means true anonymised logs from users interacting with content on the site. In my case that is two months of click data from November and December last year, in total about 2 Gb worth of raw data for videos played.&lt;/p&gt;
&lt;p&gt;In order to use the data there are a number of steps to be taken. As mentioned before the recommender system scales on the premise that we can divide the item factors for 40 million+ videos into clusters. Here is the bird&amp;#8217;s eye view of the process:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;count the number of plays per user-video pair (python)&lt;/li&gt;
	&lt;li&gt;run matrix factorisation and store the intermediate item and user vectors separately (java)&lt;/li&gt;
	&lt;li&gt;cluster the item vectors produced in step 2 &amp;#8211; currently using &lt;code&gt;scipy.cluster.vq.kmeans2&lt;/code&gt; to do this (python)&lt;/li&gt;
	&lt;li&gt;load the data into the online recommendation system and start serving recommendations (scala)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Counting&lt;/strong&gt;&lt;br /&gt;
The data comes in the following format: &lt;code&gt;... userid videoid ...&lt;/code&gt; (the dots indicate play related data) and there&amp;#8217;s one line per play. A simple python script does the trick.&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/2422153.js&quot;&gt; &lt;/script&gt;&lt;p&gt;Since I need to verify the accuracy of the recommendation I create two sets: a training set used to build the model, and a test set which will be used to verify the results. The sets are the end-result of this process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Model generation&lt;/strong&gt;&lt;br /&gt;
The implementation of the matrix factorisation algorithm is beyond the scope of my thesis (except for an understanding of how it works). I&amp;#8217;m lucky to be able to use an existing implementation of &lt;a href=&quot;http://dl.acm.org/citation.cfm?id=1511352&quot;&gt;Koren&amp;#8217;s algorithm for implicit feedback&lt;/a&gt; provided by Linas and his team at Telefonica. It is part of a larger suite of recommendation algorithms which they plan to open source, and I hope to be able to assist them in that process. For now, it&amp;#8217;s enough to say that the result of this step consists of two files: one with all items&amp;#8217; latent factors and one with all users&amp;#8217; latent factors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clustering&lt;/strong&gt;&lt;br /&gt;
I&amp;#8217;m really focusing on scalability more than the accuracy of the algorithms used. This is both an advantage and a drawback of my work. The advantage is I can be less picky about the model and how the data is supplied to the online recommendation system. Clustering is thus something I do not have to implement myself and, browsing a little for easy-to-use clustering implementations I finally settled on &lt;a href=&quot;http://docs.scipy.org/doc/scipy/reference/generated/scipy.cluster.vq.kmeans2.html&quot;&gt;scipy&amp;#8217;s k-means&lt;/a&gt;. The &lt;a href=&quot;http://en.wikipedia.org/wiki/K-means_clustering&quot;&gt;k-means algorithm&lt;/a&gt; is one of the easiest and works by grouping items into K clusters such that the item joins the cluster with the nearest mean of the items already in the cluster (see the Wikipedia article for a full explanation of the algorithm). Clustering with scipy is a breeze and the gist of the code is only four lines:&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/2422239.js&quot;&gt; &lt;/script&gt;&lt;p&gt;The output is one file per cluster with the respective item vectors and a signature file with the centroids. The latter is used to initialise the last online recommendation system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Online&lt;/strong&gt;&lt;br /&gt;
The recommender system reads the centroid file and spawns one process per centroid/cluster distributed across a set of nodes&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. Each process loads its cluster into memory and registers itself as ready to accept recommendation requests. &amp;#8220;Routers&amp;#8221; on every node routes requests based on cosine similarity between the signature and the user&amp;#8217;s request. The request contains the user&amp;#8217;s latent factors and possibly contextual information such as the last video played. Once the best cluster is determined the request is forwarded to the process responsible for that cluster which in turn computes the recommendations. Finally, the top K recommendations are returned to the user.&lt;/p&gt;
&lt;p&gt;Easy peasy.&lt;/p&gt;
&lt;p&gt;There are still some hurdles to tackle before I can test the system fully and say that it &lt;em&gt;really&lt;/em&gt; works. But today&amp;#8217;s progress is a good step in the direction of ensuring some form of qualitative results from my thesis.&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; There are still some details missing before it is fully distributed. It&amp;#8217;s coming.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Performance evaluation with JMeter</title>
      <link>http://thesis.ljungblad.nu/2012/04/19/performance_evaluation_with_jmeter</link>
      <pubDate>Thu, 19 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/19/performance_evaluation_with_jmeter</guid>
      <description>&lt;p&gt;A &lt;a href=&quot;http://paulormg.com/&quot;&gt;classmate&lt;/a&gt; asked in our irc-channel earlier today about performance testing the system he&amp;#8217;s working on. We discussed a bit about &lt;a href=&quot;http://jmeter.apache.org/&quot;&gt;JMeter&lt;/a&gt; and I thought I&amp;#8217;d share the set-up I used to, in particular, determine the &lt;strong&gt;maximum sustained throughput&lt;/strong&gt;.&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;More specifically:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The goal of these tests is to establish the approximate throughput of serving recommendations on-line and the number of machines required to handle today’s load at Tuenti.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;JMeter comes with good documentation for how to set up tests. I suggest starting with &lt;a href=&quot;http://jmeter.apache.org/usermanual/build-web-test-plan.html&quot;&gt;this tutorial&lt;/a&gt;. It does not, however, come with particularly useful graphing tools. Instead I strongly recommend installing &lt;a href=&quot;http://code.google.com/p/jmeter-plugins/&quot;&gt;the jmeter-plugins suite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For our purposes I collected the following metrics:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Response time over time&lt;/li&gt;
	&lt;li&gt;Response time distribution&lt;/li&gt;
	&lt;li&gt;Response time percentiles (cumulative distribution)&lt;/li&gt;
	&lt;li&gt;Transactions completed per second (throughput)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to determine the maximum capacity of the system I defined a test which I gradually increased the number of requests per second. Luckily there&amp;#8217;s a &lt;a href=&quot;http://code.google.com/p/jmeter-plugins/wiki/ThroughputShapingTimer&quot;&gt;Throughput Shaping Timer&lt;/a&gt; to do exactly this! I suspected the system would start to behave weirdly around 1000 requests per second and thus defined the following. It increases faster in the beginning and then slows down, but steadily increases the throughput to a total of 1700 requests per second.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/throughput_shaping_timer.png&quot; title=&quot;Throughput Shaping Timer configuration&quot; alt=&quot;Throughput Shaping Timer configuration&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The results below show that at around 1200 requests the system does start to behave weirdly. The blue line shows failed requests, and although I don&amp;#8217;t know exactly why yet, it turns out that the application is starting to spit out exceptions at this point.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/throughput_shaping_results.png&quot; title=&quot;Throughput Shaping results&quot; alt=&quot;Throughput Shaping results&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It could be worse, it could be better. Measuring is the only way of knowing as another &lt;a href=&quot;http://stream.nicholasrutherford.com/&quot;&gt;classmate&lt;/a&gt; would have put it.&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; This may not be the most academic way of doing it, but it gave me sufficient data to know where to focus our efforts.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>First user interface</title>
      <link>http://thesis.ljungblad.nu/2012/04/17/first_user_interface</link>
      <pubDate>Tue, 17 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/17/first_user_interface</guid>
      <description>&lt;p&gt;&lt;img src=&quot;images/ui_v1.png&quot; title=&quot;First user interface for recsys&quot; alt=&quot;First user interface for recsys&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It rocks! Right?&lt;/p&gt;
&lt;p&gt;And a nice quote from the Instagram talk featured on the &lt;a href=&quot;http://highscalability.com/blog/2012/4/16/instagram-architecture-update-whats-new-with-instagram.html&quot;&gt;High Scalability blog&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ideas are disposable: if one doesn’t work, you quickly move on to another.&lt;/p&gt;
&lt;/blockquote&gt;</description>
    </item>
    
    <item>
      <title>Working with Scala</title>
      <link>http://thesis.ljungblad.nu/2012/04/16/working_with_scala</link>
      <pubDate>Mon, 16 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/16/working_with_scala</guid>
      <description>&lt;p&gt;Scala is a fascinating language. It was new to me when I started on the thesis but my colleage from Telefonica promoted it, and there are some legitimate reasons for us to use it too.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;It runs on the &lt;span class=&quot;caps&quot;&gt;JVM&lt;/span&gt;. This is a significant advantage as we can use any java-library directly from Scala, for example &lt;a href=&quot;http://jblas.org/&quot;&gt;jBlas&lt;/a&gt; for some heavy-duty math computations.&lt;/li&gt;
	&lt;li&gt;It is functional making it a bliss to convert mathematical algorithms to code. It reads more or less the same way.&lt;/li&gt;
	&lt;li&gt;It is object oriented (huh?!) providing nice and easy ways to re-use and encapsulate code&lt;/li&gt;
	&lt;li&gt;It is compact. At least more compact than Java and there is less worrying about catching exceptions thanks to pattern matching.&lt;/li&gt;
	&lt;li&gt;The &lt;a href=&quot;http://www.akka.io&quot;&gt;Akka-library&lt;/a&gt; provides an actor model closely resembling Erlang&amp;#8217;s. One which I&amp;#8217;m already familiar with and makes parallel programming a heck of a lot easier.&lt;/li&gt;
	&lt;li&gt;It has &lt;a href=&quot;http://www.scalatest.org&quot;&gt;ScalaTest&lt;/a&gt; and &lt;a href=&quot;http://www.easymock.org&quot;&gt;EasyMock&lt;/a&gt; (the latter is not Scala specific though) for writing specs and mocks. I prefer the WordSpecs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The combination of Akka and JVM&amp;#8217;s performance are two main reasons behind using Scala. However, at the same time Scala does, as any language, have some drawbacks. And particularly so for the novice Scala-hacker.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;There appears to be one too many ways of solving particular problems. I have a hard time figuring out the de facto standards. Perhaps as &lt;a href=&quot;http://technically.us/code/x/the-awesomeness-of-scala-is-implicit/&quot;&gt;this blogger&lt;/a&gt; put it: &amp;#8220;Scala is almost too clever for its own good.&amp;#8221;&lt;/li&gt;
	&lt;li&gt;The sbt build tool is not as polished as it could be. It feels sluggish at times and repeatedly runs out of memory after a day usage or so (despite following the instructions to increase PermGenSize).&lt;/li&gt;
	&lt;li&gt;I have a hard time getting dependency injection &amp;#8220;done right&amp;#8221; when testing. Jonas Bonér wrote a good post on the cake pattern, but when objects starts to rely on actors and their replies it becomes a mess too. Maybe I&amp;#8217;ll write a separate post on this later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#8217;s see what comes next. For now I quite enjoy hacking in Scala and Akka.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>New popular items</title>
      <link>http://thesis.ljungblad.nu/2012/04/12/new_popular_items</link>
      <pubDate>Thu, 12 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/12/new_popular_items</guid>
      <description>&lt;p&gt;One of the challenges with using a matrix factorisation method for generating recommmendations is that new items can only be accounted for when the model is generated. And this happens only once in a while. Das et al who published the &lt;a href=&quot;http://doi.acm.org/10.1145/1242572.1242610&quot;&gt;Google News paper&lt;/a&gt; argues that because news item churn is high (news get old within 2 days roughly) they want to include new items in the recommendations immediately.&lt;/p&gt;
&lt;p&gt;At first I thought this was an issue for me too. Now I think I&amp;#8217;ve concluded that it is not really such a big issue because there are really few cases where you require items to be recommended so fast.&lt;/p&gt;
&lt;p&gt;Some &lt;a href=&quot;http://melmeric.files.wordpress.com/2011/12/from-chatter-to-headlines-harnessing-the-real-time-web-for-personalized-news-recommendation.pdf&quot;&gt;researchers at Yahoo! argue along similar lines&lt;/a&gt; to Das but with respect to tweets. In other words, they want to be able to recommend content from tweets that are so recent that even waiting for model regeneration would be too time-consuming.&lt;/p&gt;
&lt;p&gt;In my opinion, one could, argue that for news and tweets it is unnecessary to recommend the very very latest content. Instead we can treat the problem of new items separately. Possibly as a problem of detecting trends. The results of such process can easily be mixed-in with the recommendations if need be. This would enable one to focus on making good accurate recommendations without immediately worrying about new items.&lt;/p&gt;
&lt;p&gt;Now, there happens to be some work on &lt;a href=&quot;http://doi.acm.org/10.1145/1454008.1454047&quot;&gt;online updates to matrix factorisation models&lt;/a&gt; too, but that is far beyond the scope of my thesis.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>REST confusion (again)</title>
      <link>http://thesis.ljungblad.nu/2012/04/05/rest_confusion</link>
      <pubDate>Thu, 05 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/05/rest_confusion</guid>
      <description>&lt;p&gt;This &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; business is very confusing. Well, it is confusing becuase of the debate of what is really &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; and what is not. In the true sense I mean.&lt;/p&gt;
&lt;p&gt;I tend to refer to the recommendation system&amp;#8217;s external interface as &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; although I&amp;#8217;m not sure it really lives up to the standards set out by &lt;a href=&quot;http://roy.gbiv.com/&quot;&gt;Fielding&lt;/a&gt;. &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; dictates that the &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; request should be as readable as possible. Furthermore, &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; implies the request is side-effect free and can thus be cached. Fielding&amp;#8217;s blog post on the &lt;a href=&quot;http://roy.gbiv.com/untangled/2009/it-is-okay-to-use-post&quot;&gt;&lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt;/&lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; argument&lt;/a&gt; explains why. As far as I can tell from his other blog post &lt;a href=&quot;http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven&quot;&gt;&lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; APIs must be hypertext-driven&lt;/a&gt; I think I&amp;#8217;m on the right track.&lt;/p&gt;
&lt;p&gt;Querying the following today:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://service.domain.com/api/users/&amp;lt;id&amp;gt;/recommendations?factors=&amp;lt;list of numbers&amp;gt;&amp;amp;quantity=&amp;lt;int&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;will simply yield:&lt;/p&gt;
&lt;pre&gt;
{
	&quot;recommendations&quot; : [[Item, Relevance], [Item, Relevance], ... ]
	&quot;itemset&quot; : Id
}
&lt;/pre&gt;
&lt;p&gt;Nothing more nothing less. Can this be called &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; or is it simply a &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; request with a response in a &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt; format?&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Supervisor meeting</title>
      <link>http://thesis.ljungblad.nu/2012/04/03/supervisor_meeting</link>
      <pubDate>Tue, 03 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/03/supervisor_meeting</guid>
      <description>&lt;p&gt;This morning I headed up to &lt;span class=&quot;caps&quot;&gt;UPC&lt;/span&gt; for another meeting with my academic supervisor. Updated him on the latest development which in short are:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;major rewrite of the core functionality to improve fault-isolation and concurrency (and ended up with a lot cleaner codebase)&lt;/li&gt;
	&lt;li&gt;primitives for load-balancing and replication in place&lt;/li&gt;
	&lt;li&gt;performance measures indicate no measurable overhead with the latest developments &amp;#8211; request handling is still primarily consumed by getting the top K items.&lt;/li&gt;
	&lt;li&gt;writing the system architecture in the report (still more to do here)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We agreed that by the end of next week I will send a first draft for him to review my writing and structure of the thesis in more detail.&lt;/p&gt;
&lt;p&gt;The upcoming challenges that I&amp;#8217;m currently aware of are (in no particular order):&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;testing using a multi-node setup (multiple JVMs)&lt;/li&gt;
	&lt;li&gt;generate model based on an experimental offline algorithm implemented by Linas&lt;/li&gt;
	&lt;li&gt;concretise the load-balancing and replication&lt;/li&gt;
	&lt;li&gt;write :)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Work work!&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Paper review - Fast Top-k retrieval for Model Based Recommendation</title>
      <link>http://thesis.ljungblad.nu/2012/04/02/paper_review_top_k</link>
      <pubDate>Mon, 02 Apr 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/04/02/paper_review_top_k</guid>
      <description>&lt;p&gt;I&amp;#8217;ve noted earlier that there is very little research published on the systems of recommender systems. Either it is completely uninteresting (I don&amp;#8217;t think so), research doesn&amp;#8217;t need them to be big, and/or companies are not willing to disclose their system system details. Or a combination of all. Who knows? However, once in a while I stumble over articles and posts that are related and relevant for my thesis and last week Linas suggested reading &lt;a href=&quot;http://dl.acm.org/citation.cfm?doid=2124295.2124354&quot;&gt;Fast Top-k Retrieval for Model Based Recommendation&lt;/a&gt;. While it is not a system&amp;#8217;s paper directly, the authors (D. Agarwal and M. Gurevich) emphasize that new approaches must be developed to improve recommendation request performance.&lt;/p&gt;
&lt;p&gt;In essence they are tackling the same problem as I&amp;#8217;m trying to do at Tuenti. The item inventory (using their terminology) is too vast to explore for brute-force methods for computing the recommendation online. The authors continue to note that previous research mostly focused on reducing the itemset, for example by discaring older items), using some form of heuristics to minimise the set, or optimising the model algorithms.&lt;/p&gt;
&lt;p&gt;Similar to the approach we&amp;#8217;re exploring at Tuenti they divide the computation in two stages. Each item is represented by a sparse feature vector and a query item. The relevance score is computed by the dot-product of the two vectors. &lt;em&gt;What is significantly different between their assumptions and mine is that for them a large item inventory consists of 50 000 items, whereas I assume large is in the ranges of tens of millions.&lt;/em&gt; They address the scale by computing an inverted index for the documents in the first stage (remember we&amp;#8217;re trying to route using cosine-similarity).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recommendation model&lt;/strong&gt;&lt;br /&gt;
Their approach of creating the model is not based on item content and meta information. Instead they &amp;#8220;&lt;em&gt;learn&lt;/em&gt; [item] vectors by minimising the deviation from the original scores [of a function], while ensuring sparsity to reduce the index size.&amp;#8221; It basically boils down to the following equation: &lt;code&gt;ascore(d,q) = sum(q,d)&lt;/code&gt; where &lt;code&gt;d&lt;/code&gt; is the weight of the document learned from some offline machine-learning model and &lt;code&gt;q&lt;/code&gt; is the query context (such as user preferences and session context). When the request arrives, they check q against the index and returns the top-K documents using the previous &lt;code&gt;ascore&lt;/code&gt;-function. There are a lot more details but will not address that here.&lt;/p&gt;
&lt;p&gt;Using the index, they, as far as I understand, approximate the model. Hence the goal is to reduce the approximation error as much as possible, and they claim to do so by up to 85% on synthetic and real datasets.&lt;/p&gt;
&lt;p&gt;There are many interesting points in their paper though, here are some:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Previous research has focused on accuracy but not on retrieval&lt;/li&gt;
	&lt;li&gt;They treat the original model as a black box, same as I do. In other words, the system is model- and item-agnostic.&lt;/li&gt;
	&lt;li&gt;In their related work, they note that some people cached results for similar queries. An interesting twist tackle the problem.&lt;/li&gt;
	&lt;li&gt;The index construction is parallelisable to item-level.&lt;/li&gt;
	&lt;li&gt;They can do incremental updates and it is easy to add new items since there is no item-interdependency once the model-function is obtained (during offline computation).&lt;/li&gt;
	&lt;li&gt;Query distribution changes over time, hence model should be recomputed regularly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evaluation&lt;/strong&gt; &lt;br /&gt;
In my opinion they provide a relatively strong evaluation using three different datasets. Two of them are synthetically generated (10k items each) to expose specific properties in which their appoach should face challenges. The third dataset (50k items) is taken from an ad-serving site. Unfortunately for me the datasets are far from the sizes that I was hoping for.&lt;/p&gt;
&lt;p&gt;Obviously their model outperforms those that it compares to, except for in one synthetic case which was specifically designed to be a pain (basically there are no dependencies between items and their model is designed to work with some inter-dependencies). Interestingly though the two other datasets are highly non-linear and thus should be challenging to approximate. Still they perform well.&lt;/p&gt;
&lt;p&gt;Finally, as for retrieval times, they claim on average 14-16 ms for the first stage (inverted index lookup) for 100 documents. I haven&amp;#8217;t tried retrieving that many documents yet, but for 20 items I&amp;#8217;m in the lower 5 ms range for the 90th percentile, including parsing the &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; request and packing the response as json-data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two favourite quotes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Under-utilised &lt;span class=&quot;caps&quot;&gt;CPU&lt;/span&gt; anyone?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The prototype was implemented as a single-threaded Java application and run on an Intel Xeon 2.0 Ghz 8-core machine with 32gb ram.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and a nice metaphor&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Since the total number of all possible cross-products are &lt;em&gt;astronomical&lt;/em&gt;, the features are hashed into a large number of bins.&lt;/p&gt;
&lt;/blockquote&gt;</description>
    </item>
    
    <item>
      <title>Rewriting the core</title>
      <link>http://thesis.ljungblad.nu/2012/03/29/rewriting_the_core</link>
      <pubDate>Thu, 29 Mar 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/29/rewriting_the_core</guid>
      <description>&lt;p&gt;Last Monday I began focusing on the details of load-balancing between the nodes in the cluster generating recommendations. In this post I&amp;#8217;ll outline roughly what I want to achieve.&lt;/p&gt;
&lt;p&gt;The recommendation model consists of a few gigabytes of partially computed recommendations. As I&amp;#8217;ve talked about before, it is unrealistic to generate recommendations from the entire set fast enough, and hence I split the data in smaller clusters. Today it is possible to run and load clusters of recommendations on a single machine. There is one worker per cluster and a router ensuring each recommendation request is forwarded to the most relevant worker. A worker is essentially a separate process implemented as an Akka Actor. Once the request reaches the worker it computes the top-K recommendations using whatever-algorithm to do so.&lt;/p&gt;
&lt;p&gt;By now you will recognise at least two challenges with this design:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;the router may become a bottleneck, and&lt;/li&gt;
	&lt;li&gt;some clusters are bound to be more popular than others and, hence, receive significantly more requests&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Lets see each of these in more detail.&lt;/p&gt;
&lt;p&gt;One can argue that the first point is prematurely trying to optimise something which may not be a problem unless load is extreme&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. The second point, however, is a real issue. We know that a few videos are watched a lot more times than the rest. There are some more tricks here but that&amp;#8217;s related to the model generation and out of scope right now. For now all we know is that some clusters will receive more requests than others.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cluster popularity&lt;/strong&gt; &lt;br /&gt;
Since one worker is responsible for only one itemset, it is easy to spawn more workers responsible for the same itemset. In my first prototype this was not the case. After having refactored the prototype did I not only improve fault-isolation and concurrency, but also reduce code complexity and cut the number of lines to a third. Retaining all the functionality from before. It&amp;#8217;s quite rewarding to see how a design becomes simpler and simpler the more you work with it.&lt;/p&gt;
&lt;p&gt;There are more advantages to essentially replicating the workers working on the same (non-shared) cluster. Workers can be assigned the same itemset but running on different nodes. Thus also improving fault-tolerance in case of node failure. This, however, is another detail that I have not begun exploring yet and will have to wait too.&lt;/p&gt;
&lt;p&gt;Design-wise I&amp;#8217;m facing a number of questions related to the replication procedure:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Who replicates workers?&lt;/li&gt;
	&lt;li&gt;When and on what grounds is replication triggered?&lt;/li&gt;
	&lt;li&gt;How will this work when a worker may be started at any node?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Compared to Nick I&amp;#8217;m not &lt;a href=&quot;http://stream.nicholasrutherford.com/post/20022459072/abstract-1&quot;&gt;trying to do any fancy machine-learning algoritms&lt;/a&gt; to determine when to increase the number of workers per itemset. What I&amp;#8217;m looking for is a rudimentary approach that works good enough.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Routing bottleneck&lt;/strong&gt;&lt;br /&gt;
A router consists of a registry which maps cluster signatures to workers. Determining the worker to use is based on calculating the cosine-similarity between the signature and the context that is attached in the request. With a dataset with 40M items, each cluster containing 40K items, the registry contains 1000 signatures. The registry needs updating if a worker process is killed, is restarted, or added. The router is also implemented as an Akka Actor and thus share no memory with other processes. Due to updates to the registry it becomes more cumbersome to replicate the router as data consistency have to be considered. For example, if a worker dies it must be updated in both routers.&lt;/p&gt;
&lt;p&gt;Granted, consistency is not our biggest concern. After all serving recommendations is an add-on feature to the total user experience. And if they are not completely in sync or up to date with the available workers then the controller will automatically return default recommendations (for example most watched videos this week). Needless to say, we want to minimise the number of misses.&lt;/p&gt;
&lt;p&gt;My idea for now is to add some kind of listener at each router. It would track all live workers, and if one dies, remove it from its registry. The question then becomes: who is responsible for ensuring a new worker is added in its place? I could have the workers register with each router as they start. The drawback with this approach (I tried it in my first prototype) is that creating the registry becomes a tangled mess with some possibly uninstantiated data that continuously need to be checked.&lt;/p&gt;
&lt;p&gt;Even if I do not run multiple routers on one node, there still has to be routers on each node, all able to tell where all workers are. Akka provides location transparency (same as in Erlang). So maintaining the registries up to date is still an issue.&lt;/p&gt;
&lt;p&gt;Suggestions? Bring them up in #emdc@freenode or &lt;a href=&quot;mailto:marcus@ljungblad.nu&quot;&gt;e-mail&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; Note to self: measure this&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Re-run with bigger dataset</title>
      <link>http://thesis.ljungblad.nu/2012/03/27/rerun_with_bigger_data</link>
      <pubDate>Tue, 27 Mar 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/27/rerun_with_bigger_data</guid>
      <description>&lt;p&gt;Last Friday I started to run with real-size data in the prototype. Some rudimentary testing indicated it worked fairly well and today I wanted to see how it ran using the JMeter tests that I had defined a few weeks back.&lt;/p&gt;
&lt;p&gt;Everything runs on my machine with 4 cores. However, since the test is always requesting recommendations for the same user this isn&amp;#8217;t really a fair test. Each request will be routed to the same cluster of recommendations, and hence, to the same actor. This also means that Tomcat can do its optimisations (whatever those may be) and ensure that the data that is being requested frequently is cached.&lt;/p&gt;
&lt;p&gt;I want to refactor some code to increase fault-isolation and concurrency amongst the actors and the data they are in charge of. Once that is done I will try to create a more dynamic test.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/load-over-time-v2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Good part is, graphs so far looks okish. Except for the blue line which indicates responses are lost. The 90th percentile is completed around 8.5 ms.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Writing every day</title>
      <link>http://thesis.ljungblad.nu/2012/03/22/writing_everyday</link>
      <pubDate>Thu, 22 Mar 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/22/writing_everyday</guid>
      <description>&lt;p&gt;Before I started working on this thesis I had the idea that I would write something everyday. To date there are 39 posts here, which two and a half month in, suggests I&amp;#8217;m not exactly there. That said, the idea of writing everyday is twofold. It is to track my progress with the thesis, and secondly, it is to see how my learning and perception of the work changes over time.&lt;/p&gt;
&lt;p&gt;Fred Wilson, the guy behind with &lt;a href=&quot;http://www.avc.com/&quot;&gt;the popular blog &lt;span class=&quot;caps&quot;&gt;AVC&lt;/span&gt;&lt;/a&gt; recently gave a short talk about &lt;a href=&quot;http://entrepreneurdesigners.tumblr.com/post/19635228919/week-4-what-is-a-company-and-why-does-one-start-it&quot;&gt;why he is blogging&lt;/a&gt;. One particular thought of his resonate with me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By putting it down on paper, it helps me crystalise my thoughts on that [matter].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is many times for this reason that whatever appears on this blog is not always straightforward to anyone else. In other words, I write what is valuable to me more so than for anyone else. No offense. My personal blog at &lt;a href=&quot;http://ljungblad.nu&quot;&gt;ljungblad.nu&lt;/a&gt; contains a broader mix, but mostly I write for exactly the same reason there.&lt;/p&gt;
&lt;p&gt;Many people blogging, writing, or producing stuff in general have a fear of shipping. A fear of pressing send on that e-mail, or publish on that blog post. It can be quite intimidating to get things wrong, but that will happen once in a while whether you want it or not. I tend to believe I got over the shipping part, and this ultimately lead me to appreciate when people take time to give constructive feedback more.&lt;/p&gt;
&lt;p&gt;Finally, Fred continues by suggesting that you &lt;em&gt;write opinion&lt;/em&gt;. This is beautiful and why, or this sucks and explain why. Always explain why. It relates to &amp;#8220;crystalising your thoughts&amp;#8221; and is more valuable than just recalling It&amp;#8217;s a good advice that I&amp;#8217;ll try to adopt a little more.&lt;/p&gt;
&lt;p&gt;Food for thought.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Iteration 2 - Routing</title>
      <link>http://thesis.ljungblad.nu/2012/03/20/iteration_2_routing</link>
      <pubDate>Tue, 20 Mar 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/20/iteration_2_routing</guid>
      <description>&lt;p&gt;Yesterday I finished the first, albeit fairly naive, version of finding the right chunk of itemsets to use for recommendations (described here). As I kind of hinted at myself I was overdoing it and a much simpler solution was the way to go. But in spite of this awareness, finding the actual solution is never as easy. Many thanks to Linas and Toni for their input which lead to a working routing mechanism.&lt;/p&gt;
&lt;p&gt;With a &amp;#8220;complete&amp;#8221; prototype of the system, this also marked the end of the first iteration (three days later than planned). In this second iteration I will narrow in on the routing further by exploring the following:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Alternative routing mechanisms to cosine-similarity&lt;/li&gt;
	&lt;li&gt;Hierarchical routing, i.e chunks may be grouped together in a tree&lt;/li&gt;
	&lt;li&gt;Parallel requests, combining results from multiple chunks in a &amp;#8220;roll-up&amp;#8221;-like function&lt;/li&gt;
	&lt;li&gt;Continuous measurements on real(istic) data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Except the obvious surprises of course.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Code coverage in Scala</title>
      <link>http://thesis.ljungblad.nu/2012/03/20/code_coverage</link>
      <pubDate>Tue, 20 Mar 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/20/code_coverage</guid>
      <description>&lt;p&gt;Before I continue with iteration 2 I wanted to review how I&amp;#8217;m testing what I&amp;#8217;m building. In essence, I try to follow &lt;a href=&quot;http://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;&lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt;&lt;/a&gt; as strictly as possible. Meaning, I run the tests before writing any code to ensure that it really does break or fail, implement the feature/function, run the tests again, refactor, test and repeat.&lt;/p&gt;
&lt;p&gt;However, as the code evolved I felt there were cases, especially corner-cases, not being tested at all. Especially a I had a creepy suspicion that one of my tests was trying to cover too much in one go, and hence when it failed it was hard to pinpoint its cause, many times leading to the old-school printf() debug technique.&lt;/p&gt;
&lt;p&gt;To investigate I hooked in the &lt;a href=&quot;https://bitbucket.org/jmhofer/jacoco4sbt/wiki/Home&quot;&gt;Jacoco Code Coverage plugin&lt;/a&gt; to &lt;a href=&quot;https://github.com/harrah/xsbt&quot;&gt;sbt&lt;/a&gt; and ran &lt;code&gt;jacoco:cover&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/jacoco_overview.png&quot; title=&quot;Overview of code coverage report&quot; alt=&quot;Overview of code coverage report&quot; /&gt;&lt;/p&gt;
&lt;p&gt;My immediate reaction was: &lt;strong&gt;25%?! &lt;span class=&quot;caps&quot;&gt;WTF&lt;/span&gt;!?!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s a catch, or a short-coming in the Jacoco tool, though. As numerous classes are extended or have traits mixed-in, especially the Akka-actors, there is a lot of unused code. One could argue, correctly so, that there should be test-cases trying some of these scenarios. For example, what happens if an actor is killed in the midst of processing a request? This will trigger code in branches that are never executed during normal operation.&lt;/p&gt;
&lt;p&gt;On the other hand there is also more mysterious pieces of code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/jacoco_details.png&quot; title=&quot;Detailed code coverage report&quot; alt=&quot;Detailed code coverage report&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s a bit hard to see in the screenshot, but there seems to be some &lt;a href=&quot;http://ofps.oreilly.com/titles/9780596155957/FunctionalProgramming.html&quot;&gt;partial functions&lt;/a&gt; that evade the tests almost completely. These, as far as I can tell, are coming from the Akka libraries. Similar to functions which are unused in traits and extended classes it would be interesting to have an option in Jacoco to exclude these from being evaluated.&lt;/p&gt;
&lt;p&gt;Consequently, after going through the report in more detail my initial &lt;span class=&quot;caps&quot;&gt;WTF&lt;/span&gt; has been reduced. The fact remains, however, that one test in particular is absolutely too broad in scope. Fixing this now.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Routing to the most relevant itemset(s)</title>
      <link>http://thesis.ljungblad.nu/2012/03/15/nearest_neighbour_search_problem</link>
      <pubDate>Thu, 15 Mar 2012 00:00:00 -0700</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/15/nearest_neighbour_search_problem</guid>
      <description>&lt;p&gt;The dataset I&amp;#8217;m working with contains more than 40M items and we want to be able to use most of it to make recommendations online. It is unfeasible, as we have seen in measurements, to compute the most relevant sets from the entire dataset for three reasons: the average compute time is too high for real-time responses, the entire dataset has to be stored in memory (depends on your machine obviously), and finally, as the dataset grows this approach will not scale horizontally.&lt;/p&gt;
&lt;p&gt;There are, at least, two approaches to address the dataset size. First, by discarding &amp;#8220;old&amp;#8221; data or removing portions of the long-tail it would be possible to reduce the dataset size significantly. Reducing the size may impact the quality and scope, or breadth, of the recommendations made. It remains to be determined how many items are sufficient to generate adequately relevant recommenadations.&lt;/p&gt;
&lt;p&gt;The second alternative, and the one I&amp;#8217;m currently working with, assumes we can split the dataset into smaller chunks during the off-line computation. Each chunk represents a cluster of related items which are constructed offline by some clustering algorithm. For the moment I only assume these chunks are made available to the online cluster somehow. This leads to the following challenge which can be formulated as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When a recommendation requests arrives to a node in the cluster, how do I know which chunk of items to use when generating the recommendations?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The recommendation request has the user&amp;#8217;s preference factors, and in the future context information, attached to it. Given that each chunk can be described by a centroid, a unique representative id, I could formulate a distance function to identify which chunk is closest to the user&amp;#8217;s preferences and/or session context. The approaches that I&amp;#8217;ve looked at for determining the most relevant chunk(s) are locality-sensitive hashing and kd-trees, both which are known solutions to the nearest-neighbour search problem. &lt;a href=&quot;http://www.slaney.org/malcolm/yahoo/Slaney2008-LSHTutorial.pdf&quot;&gt;Read this for a nice introduction to &lt;span class=&quot;caps&quot;&gt;LSH&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, my worries with the &lt;span class=&quot;caps&quot;&gt;LSH&lt;/span&gt; approach are several:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;can the centroids correctly describe the chunks?&lt;/li&gt;
	&lt;li&gt;does &lt;span class=&quot;caps&quot;&gt;LSH&lt;/span&gt; or the chunks mask the advantages of the matrix factorisation model and the eventual re-ranking with the user preferences?&lt;/li&gt;
	&lt;li&gt;so far I&amp;#8217;ve only tried an &lt;span class=&quot;caps&quot;&gt;LSH&lt;/span&gt; implementation using signature hashes (which are used to reduce the dimensionality into an approximation). This is easy as the signatures contain only positive integers. However, if I were to skip the signatures (there are not that many dimensions anyway) the &lt;span class=&quot;caps&quot;&gt;LSH&lt;/span&gt; would have to operate on the latent factors directly, making me unsure how to define the hash functions.&lt;/li&gt;
	&lt;li&gt;maybe this is overly complicated for what I&amp;#8217;m trying to achieve, are there any simpler alternatives for nearest-neighbour? Perhaps if I can mix in some domain specific knowledge it becomes a lot simpler?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&amp;#8217;s also a (big?) chance I&amp;#8217;m looking at the problem in the wrong way. I&amp;#8217;m kind of stuck at this problem at the moment.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Work process</title>
      <link>http://thesis.ljungblad.nu/2012/03/08/work_process</link>
      <pubDate>Thu, 08 Mar 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/08/work_process</guid>
      <description>&lt;p&gt;One of the most exciting things with building an online recommendation system from scratch is that one can apply many different concepts and theories in practice, especially concepts from a courses and litterature that we have studied in &lt;span class=&quot;caps&quot;&gt;EMDC&lt;/span&gt;. At the same time, it is very dangerous. In this post I thought I would outline a bit about the work process. Partly to get it down on paper for later reference, and partly to track how (and if) it evolves.&lt;/p&gt;
&lt;h3&gt;Pre-system development&lt;/h3&gt;
&lt;p&gt;In order to get an idea of the complexity and the architecture of the online recommendation system, both Toni and I spent considerable time in the beginning reading papers, testing libraries, evaluating existing systems, and most importantly, building throw-away prototypes. We built prototypes in Scala, &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;, and Python covering specific aspects of the offline algorithm, the online part, as well as more general architectual concepts.&lt;/p&gt;
&lt;h3&gt;Iterations&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;ve tried to divide the development of the system in two week iterations (most teams at Tuenti also work in two-week sprints). The idea is that each iteration should finish with all tests passing, and that every part of the system have received some attention (even if only minor edits).&lt;/p&gt;
&lt;p&gt;As with all early development, the code is very instable and parts sometimes changes several times a day. There have been days where I come to work the following morning and thinking &amp;#8220;what the he** did I write yesterday&amp;#8221;. Luckily, there are days where the opposite is true too and I can direct my attention to another part of the system.&lt;/p&gt;
&lt;p&gt;Before finishing the second iteration (which according to my initial plan should be done on March 15) I wanted to make sure I have touched upon all the areas of the system. Most components so far are very dumb, some return static values, other more comprehensive results. However, it does hang together and seeing the integration tests pass makes you feel good. Gradually I&amp;#8217;m replacing each of the stubs and, for example, yesterday I spent most time sketching out the gossip algorithm that will share information about the available itemsets and their respective current load. Eventually this data will be made available to the load-balancer (instead of the current brute-force load-balancing which is in place now).&lt;/p&gt;
&lt;h4&gt;Writing&lt;/h4&gt;
&lt;p&gt;A thesis is no thesis without a written report. At least as far as I know. Though I haven&amp;#8217;t started writing anything yet my intention is to do so shortly. My supervisor asked if I could bring something in writing until our next meeting, which so happen to coincide with my second iteration deadline. Text, as much as code, require thinking, editing, refactoring, in short a lot of attention. Thus I feel it would be a good idea to already now devote some time every week to writing&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3&gt;Deadlines&lt;/h3&gt;
&lt;p&gt;As I know them today:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Iteration 2: March 15 &amp;#8211; all parts outlined in system, at least stubs&lt;/li&gt;
	&lt;li&gt;Iteration 3: March 30 &amp;#8211; recommendation routing&lt;/li&gt;
	&lt;li&gt;Iteration 4: April 15 &amp;#8211; load-balancing&lt;/li&gt;
	&lt;li&gt;Iteration 5: April 30 &amp;#8211; metrics&lt;/li&gt;
	&lt;li&gt;Iteration +: This is still too far off to say anything about. I could argue that even end of April is way too far ahead. Well, it&amp;#8217;s never too late to change it around a bit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And the current plan is to present the thesis in June.&lt;/p&gt;
&lt;p&gt;Work work!&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; This isn&amp;#8217;t really anything new but somehow it is always difficult to start on time and writing tends to be left for the last minute.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Worth migrating from Akka 1.3 to 2.0?</title>
      <link>http://thesis.ljungblad.nu/2012/03/08/switching_akka_version</link>
      <pubDate>Thu, 08 Mar 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/08/switching_akka_version</guid>
      <description>&lt;p&gt;A few days ago &lt;a href=&quot;http://akka.io/news/2012/03/06/akka-20-released.html&quot;&gt;Akka 2.0 was officially released&lt;/a&gt;. It&amp;#8217;s been available as a release candidate for a while and should be fairly stable (sufficient for what I&amp;#8217;m working on). However, the new release isn&amp;#8217;t as easy to migrate too as one would wish. It includes several changes to the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; and structural changes to how actors are created and accessed.&lt;/p&gt;
&lt;p&gt;That said, &lt;a href=&quot;http://typesafe.com/&quot;&gt;Typesafe et al&lt;/a&gt; have made an effort to &lt;a href=&quot;http://doc.akka.io/docs/akka/2.0/project/migration-guide-1.3.x-2.0.x.html&quot;&gt;smooth the transition&lt;/a&gt; for developers by packing the &amp;#8220;old api&amp;#8221; in an isolated jar which can run alongside the 2.0 code. This enables gradual migration of code. Though it looks &amp;#8220;easy&amp;#8221; on paper, I&amp;#8217;m not convinced it is as easy in practice.&lt;/p&gt;
&lt;p&gt;Pros of switching:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;ActorSystems which makes it possible to run multiple akka deployments on the same &lt;span class=&quot;caps&quot;&gt;JVM&lt;/span&gt; &amp;#8211; this is a huge win for testability and to me seems like one of the major design improvements in akka 2.0.&lt;/li&gt;
	&lt;li&gt;Geting access to the new Router package would simplify the implementation of the load-balancer&lt;/li&gt;
	&lt;li&gt;Nicer APIs :)&lt;/li&gt;
	&lt;li&gt;The codebase is still relatively small so it is easier to switch now&lt;/li&gt;
	&lt;li&gt;Google&amp;#8217;s references to the docs would be more useful. Today I often manually have to switch back to 1.3 only to discover that the feature I was looking at doesn&amp;#8217;t exist.&lt;/li&gt;
	&lt;li&gt;Living on the edge is fun&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Akka 1.3 works&lt;/li&gt;
	&lt;li&gt;It would take time from new development&lt;/li&gt;
	&lt;li&gt;As &lt;a href=&quot;http://lalith.in&quot;&gt;Lalith&lt;/a&gt; pointed out &amp;#8220;you can do a PhD on an old release&amp;#8221;, i.e there is no need to switch&lt;/li&gt;
	&lt;li&gt;Most blogs with tips and tricks on akka mostly refers to 1.3 (obviously this changes over time)&lt;/li&gt;
	&lt;li&gt;All the unknowns that I have to face if switching&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Moreover, there are some intriguing items on the (unofficial?) &lt;a href=&quot;https://docs.google.com/document/pub?id=1CMz_MEQA8oPcGw9oaFdq_KYYFB_5qZjsDYYwuXfZhBU&amp;amp;pli=1&quot;&gt;roadmap&lt;/a&gt; of akka, specifically with respect to clustering and elasticity. These properties are often challenging to develop (at least in Erlang, and I believe it is the same in akka 1.3) and it keeps reappearing as an issue. Making it part of the akka-library should open quite a few new doors.&lt;/p&gt;
&lt;p&gt;Lets think about this migration decision over lunch.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Status update</title>
      <link>http://thesis.ljungblad.nu/2012/03/05/status_update</link>
      <pubDate>Mon, 05 Mar 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/05/status_update</guid>
      <description>&lt;p&gt;Compiled a todo-list of things to implement / look at. No priorities assigned yet and everything is probably not relevant.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Check architecture against original plan and update accordingly&lt;/li&gt;
	&lt;li&gt;Investigate distributed setup and testing with Akka&lt;/li&gt;
	&lt;li&gt;Remote actors identification and lookup &amp;#8211; discovery of remote nodes&lt;/li&gt;
	&lt;li&gt;Change load-balancer to support remote actors&lt;/li&gt;
	&lt;li&gt;Dynamically redistribute itemsets if node is down or itemset is unavailable or overloaded &amp;#8594; this implies changing the index-mechanism too.&lt;/li&gt;
	&lt;li&gt;Fake lookups of preferences&lt;/li&gt;
	&lt;li&gt;Gossip health status of itemsets&lt;/li&gt;
	&lt;li&gt;Load and register itemsets to actors and trigger reload&lt;/li&gt;
	&lt;li&gt;Define bootstrapping procedure&lt;/li&gt;
	&lt;li&gt;Add proper configurability&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And less code related&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Define a preliminary title for the thesis&lt;/li&gt;
	&lt;li&gt;Draft an outline of the report to next supervisor meeting&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;http://www.wowwiki.com/Quotes_of_Warcraft_III/Orc_Horde#Orc_Peon&quot;&gt;Work work!&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Mind your language</title>
      <link>http://thesis.ljungblad.nu/2012/03/05/mind_your_language</link>
      <pubDate>Mon, 05 Mar 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/05/mind_your_language</guid>
      <description>&lt;p&gt;In Erlang we often refer to processes as children, and shutting down a child is often called &lt;em&gt;kill children&lt;/em&gt;. What a horrible thought! In Scala the processes are referred to as actors and we kill those too. Albeit slightly better than slaughtering unknowing youngsters.&lt;/p&gt;
&lt;p&gt;*nix is also a part of a dark conspiracy with &lt;em&gt;killall&lt;/em&gt; and its violent sibling &lt;em&gt;kill&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;C, on the other hand, is a happy language. There data is set &lt;em&gt;free()&lt;/em&gt;, which sounds like we&amp;#8217;re letting it of to a better place. I like that.&lt;/p&gt;
&lt;p&gt;Where did language designers get their brutal metaphors from?&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Curse of Dimensionality</title>
      <link>http://thesis.ljungblad.nu/2012/03/02/curse_of_dimensionality</link>
      <pubDate>Fri, 02 Mar 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/02/curse_of_dimensionality</guid>
      <description>&lt;p&gt;Came across an interesting phenomena a few days back when I was reading about dimensionality reduction, i.e using techniques to reduce the number of dimensions of some data. At that time I didn&amp;#8217;t know a term exists to describe it: &lt;a href=&quot;http://en.wikipedia.org/wiki/Curse_of_dimensionality&quot;&gt;The curse of dimensionality&lt;/a&gt;. &lt;a href=&quot;http://www.quora.com/What-is-the-curse-of-dimensionality&quot;&gt;Kevin Lacker&lt;/a&gt; explains the problem in simple terms on Quora:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let&amp;#8217;s say you have a straight line 100 yards long and you dropped a penny somewhere on it. It wouldn&amp;#8217;t be too hard to find. You walk along the line and it takes two minutes.&lt;/p&gt;
&lt;p&gt;Now let&amp;#8217;s say you have a square 100 yards on each side and you dropped a penny somewhere on it. It would be pretty hard, like searching across two football fields stuck together. It could take days.&lt;/p&gt;
&lt;p&gt;Now a cube 100 yards across. That&amp;#8217;s like searching a 30-story building the size of a football stadium. Ugh.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After three dimensions it becomes difficult to find physical metaphors, and the problem is more evident when dimensions increase significantly. You see the challenge? The phenomena is found in several areas related to analysing or interpreting data, for example, data mining. When I first started working on recommendations using matrix factorization I thought 20 latent factors to describe a user&amp;#8217;s preferences sounded like quite a lot of dimensions. As far as my memory can tell, I&amp;#8217;ve never written an application where I needed more than a three or four. Thus, 20 dimensions was rather abstract. Today it&amp;#8217;s less so, although some of part of the recommendation modelling is still equivalent to &lt;a href=&quot;http://en.wikipedia.org/wiki/Black_magic&quot;&gt;black magic&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While working on the implemenation of Minhash and Locality-Sensitive hashing I&amp;#8217;ve come to realise that 20 dimensions are still pretty few and, luckily, the curse of dimensionality &lt;em&gt;might&lt;/em&gt; not be kicking in. Because the challenge is that some algorithms that are designed for low dimensions perform horrible on large dimensions, and vice versa. Good for me I guess :)&lt;/p&gt;
&lt;p&gt;Now lets see&amp;#8230; where was I?&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Meeting my supervisor</title>
      <link>http://thesis.ljungblad.nu/2012/03/01/meeting_my_supervisor</link>
      <pubDate>Thu, 01 Mar 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/03/01/meeting_my_supervisor</guid>
      <description>&lt;p&gt;I started my thesis work in January and haven&amp;#8217;t since met my academic supervisor. In fact, I didn&amp;#8217;t really have one until two weeks ago. Today I met Prof. &lt;a href=&quot;https://twitter.com/#!/PepeBalcazar&quot;&gt;José L Balcázar&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We discussed a number of things, some which might be useful to highlight are:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deviations&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;All projects drift. Whether we like it or not does not matter, they all drift. Each project also drifts differently; some fluctuating weekly or even daily, and some over a long period. One of the reasons I&amp;#8217;m keeping this blog is to be able to track a the project&amp;#8217;s drift. Prof. Balcázar also suggested taking a minute or two everyday looking at all the pieces of the puzzle and the relationship between the pieces. The day they do not make sense or the process takes more time than two minutes it is time to spend a few hours thinking through everything thoroughly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One of my task as your supervisor is to make sure you do not build a website and sell it as a master thesis with fancy words like Joomla. In your case we have a different problem: to make sure you do a master thesis and not a PhD thesis.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This has, and still is, one of the major challenges for me too. There are simply too many interesting threads to follow up on and narrowing down on the most important ones is hard. Within the next few days I&amp;#8217;ll try to write down a title of my thesis as a way of defining the scope more precisely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Second System Effect&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We also discussed second-generations of software, particularly with respect to the problem you are trying to tackle. The term above is from &lt;a href=&quot;http://en.wikipedia.org/wiki/Fred_Brooks&quot;&gt;Fred Brooks&amp;#8217;s&lt;/a&gt; quintessential book &lt;a href=&quot;http://en.wikipedia.org/wiki/The_Mythical_Man-Month&quot;&gt;The Mythical Man-Moth&lt;/a&gt; in which he describes the effect as the second version of a system being bloated and clunky compared to the first version. It is certainly something to have in mind, especially as Tuenti already have a naive recommendation engine for video content (although as mentioned earlier it does not account for contextual data or user preferences).&lt;/p&gt;
&lt;p&gt;Overall, I&amp;#8217;m very happy and I&amp;#8217;m looking forward to his valuable insights on this project. For the next meeting I also hope to present something in writing. Should be a good push to get started with the text too, even if only extremely rudimentary.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Finding a needle in a haystack</title>
      <link>http://thesis.ljungblad.nu/2012/02/27/finding_sets</link>
      <pubDate>Mon, 27 Feb 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/02/27/finding_sets</guid>
      <description>&lt;p&gt;As I&amp;#8217;ve mentioned previously doing on-line recommendations of all 40M videos and 13M+ users isn&amp;#8217;t exactly reasonable (within the time constraints given). We&amp;#8217;ve been approaching the problem by creating a partial model offline and then loading this one to memory of the online cluster. When a request arrives, we complete the recommendation by applying the user preferences and session context. Sounds good in theory and we&amp;#8217;re now in the stage of evaluating whether this also works in practice.&lt;/p&gt;
&lt;p&gt;Since it is unreasonable to go through all 40M items online and select the top-K items from such a large list the idea is to cluster the items in smaller sets. Lets say, for example, that each cluster is 10 000 items large&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, then we&amp;#8217;ll end up with 4 000 such sets. Out of those we need to pick only a few, and preferably those should also be the most relevant sets to the user&amp;#8217;s session.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enter minhash.&lt;/strong&gt; The algorithm works by generating signatures of larger sets such that they can be compared against each other faster. One of the more popular (and easy) ways to measure similarity is using the Jaccard similarity which basically is &lt;code&gt;setA.intersection(setB).length / setA.union(setB).length&lt;/code&gt;. Applying the Jaccard similarity measure on the signature sets turns out to be a very good approximation on the true similarity.&lt;/p&gt;
&lt;p&gt;How are signatures generated? I hacked together this function to create them:&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/1922816.js&quot;&gt; &lt;/script&gt;&lt;p&gt;It takes a character matrix of the sets that we want to &amp;#8220;compress&amp;#8221; and a list of random hash functions. Each hash function is some variation of &lt;code&gt;Ax+1 mod l&lt;/code&gt; where &lt;code&gt;l&lt;/code&gt; is the height of the character matrix.&lt;/p&gt;
&lt;p&gt;As we would still end up with the same number of signatures as the original, it may still be too computationally expensive to discover which sets are the most relevant. We can combine the technique of minhashing with &lt;em&gt;Locality Sensitive Hashing&lt;/em&gt; to reduce the number of comparisons required to find similar items. This algorithm groups signatures into buckets by hashing portions of each set (think of it as horizontal slices of the signature matrix). The intuition is that multiple columns can be hashed to the same bucket, thus indicating that they are similar. The likelihood of similarity increases with the size of the slice (or band is it is also called). Consequently, this algorithm&amp;#8217;s drawback is that it yields both false positives and false negatives and I&amp;#8217;m yet unsure to what extent this affects the quality of future recommendations.&lt;/p&gt;
&lt;p&gt;For a more detailed explanations of the Minhash and Locality Sensitive Hashing algorithms I suggest reading chapter 3 in Rajaraman and Ullman&amp;#8217;s book on &lt;a href=&quot;http://infolab.stanford.edu/~ullman/mmds.html&quot;&gt;Mining of Massive Datasets&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; Computing the predicted ratings of 10 000 items for a user takes only a few milliseconds using jBlas.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Handling failures</title>
      <link>http://thesis.ljungblad.nu/2012/02/20/handling_failures</link>
      <pubDate>Mon, 20 Feb 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/02/20/handling_failures</guid>
      <description>&lt;p&gt;In a meeting earlier today the question of handling machine failures was raised. Dealing with failures is obviously something one cannot take lightly and there are several approaches available. It is always, however, good to first explicate the requirements. What user-experience do we want to provide? In some scenarios (like when withdrawing money) it is not ok to fail, while in others (getting your friend&amp;#8217;s latest facebook update) some degree of failure is ok. In extreme cases, maybe it is even ok to tell the user that the service is unavailable, although that is more certain to stir up some frustration.&lt;/p&gt;
&lt;p&gt;Secondly, one need to think about what level of failures to handle. There&amp;#8217;s huge difference between handling machine failures and datacenter failures. Dealing with machine failures can be addressed within the application or using external hardware components. There&amp;#8217;s also a design decision (or philosophical decision) to make whether the system should be aware of what type of failure guarantees it can provide or not: i.e cluster or machine-aware. Each will require different semantics and consistency considerations.&lt;/p&gt;
&lt;p&gt;In the service component that we&amp;#8217;re building for generating recommendations on-the-fly, we can integrate methods for replication of the data model to increase availability of recommendations to serve. There are, at least, four possible replication schemes with varying complexity to consider:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;If the whole model fits in &lt;span class=&quot;caps&quot;&gt;RAM&lt;/span&gt; it can be replicated on all machines. Since, at least initially, the model is only updated once a day, there are few consistency issues to worry about. As long as the cluster can handle all incoming requests all but one machine may fail.&lt;/li&gt;
	&lt;li&gt;If the whole model does not fit in &lt;span class=&quot;caps&quot;&gt;RAM&lt;/span&gt;, it can be sharded and replicated amongst a subset of machines in the cluster. This could result in certain parts of the model not being available to recommend, but if the index used to keep track of the itemsets is kept up to date, the &amp;#8220;most similar&amp;#8221; items can still be served. Here a subset but one machine may fail to ensure that some data is served (albeit it may not be the most accurate recommendations).&lt;/li&gt;
	&lt;li&gt;An alternative to version two is to split the data such that only some users are affected by machine outages. This would depend on how the model is split across the cluster and how the index of the itemsets are kept up to date.&lt;/li&gt;
	&lt;li&gt;Finally, one alternative is to not do any replication to handle failures and simply serve static or no recommendations at all if a failure occur.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Perhaps the question we should ask ourselves is: How little redundancy can we get away with?&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Drawing sequence diagrams</title>
      <link>http://thesis.ljungblad.nu/2012/02/14/drawing_sequence_diagrams</link>
      <pubDate>Tue, 14 Feb 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/02/14/drawing_sequence_diagrams</guid>
      <description>&lt;p&gt;Yesterday I had a need to persist my (fancy) sequence diagram that I had jotted down on a piece of paper to illustrate the flow of a request in the system. It seems my notebook is not as reliable as a backed-up mercurial repository&amp;#8230; I discussed with &lt;a href=&quot;http://stream.nicholasrutherford.com/&quot;&gt;Nick&lt;/a&gt; and &lt;a href=&quot;http://blog.padowi.se/&quot;&gt;Patrik&lt;/a&gt; to find &lt;strong&gt;easy, expressive yet simple, and free&lt;/strong&gt; tools for drawing these types of diagrams.&lt;/p&gt;
&lt;p&gt;I settled on &lt;a href=&quot;http://www.websequencediagrams.com/&quot;&gt;WebSequenceDiagrams&lt;/a&gt; which neatly solved the job (albeit not free in the true sense). Patrik later pointed me to &lt;a href=&quot;http://blockdiag.com/en/&quot;&gt;BlockDiag&lt;/a&gt; which &lt;strong&gt;is&lt;/strong&gt; free and also looks straightforward. Next time I&amp;#8217;ll give it a shot!&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Math libraries (cont)</title>
      <link>http://thesis.ljungblad.nu/2012/02/09/math_libraries_cont</link>
      <pubDate>Thu, 09 Feb 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/02/09/math_libraries_cont</guid>
      <description>&lt;p&gt;And the winner is &lt;a href=&quot;http://eigen.tuxfamily.org/index.php?title=Main_Page&quot;&gt;Eigen&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Yes, it wasn&amp;#8217;t even mentioned in the previous post. In fact I mixed the names of uBlas and Eigen up. Perhaps not a big surprise that C++ outperforms the others. More significant is that the library is single-threaded and yet compares faster than the parallel libraries jBlas and ParallelColt. The difference, however, is marginal: ~6900 ms vs ~7900 ms.&lt;/p&gt;
&lt;p&gt;The jumbo spot is, also not surprisingly, held by &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;. Memory explodes after 1M items for which it takes a rock-steady 220 seconds to compute &lt;code&gt;m*m.transpose()&lt;/code&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Evaluating math libraries</title>
      <link>http://thesis.ljungblad.nu/2012/02/09/math_libraries</link>
      <pubDate>Thu, 09 Feb 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/02/09/math_libraries</guid>
      <description>&lt;p&gt;Matrix factorization isn&amp;#8217;t an algorithmically cheap technique. Quite the opposite. Most algorithms are based on approximating the values until the root mean squared error is sufficiently small (the definition of small is yet another variable to decide on).&lt;/p&gt;
&lt;p&gt;There is one particular operation which has both a large memory and cpu footprint:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;matrix * matrix.transpose()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Looks innocent? However, the matrix has the following dimensions: 20 &amp;#215; 40,000,000 which complicates things a bit. In fact, it could be a lot larger (and many others probably calculate much bigger matrices), but at the same time it is only a tiny part of the whole equation.&lt;/p&gt;
&lt;p&gt;That said, Toni and I have spent some time profiling existing math libraries which provides smart matrix data structures and efficient algorithms. At the moment we have tried the following:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Java&lt;/strong&gt;
	&lt;ul&gt;
		&lt;li&gt;ParallelColt&lt;/li&gt;
		&lt;li&gt;Apache Commons Math&lt;/li&gt;
		&lt;li&gt;jBLAS&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Scala&lt;/strong&gt;
	&lt;ul&gt;
		&lt;li&gt;Scalala&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;C++&lt;/strong&gt;
	&lt;ul&gt;
		&lt;li&gt;uBLAS&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;&lt;/strong&gt;
	&lt;ul&gt;
		&lt;li&gt;PEAR_Math&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We haven&amp;#8217;t got the final verdict yet, but let&amp;#8217;s say &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; is struggling way behind. We couldn&amp;#8217;t even get it to run on matrices larger than 1,000,000.&lt;/p&gt;
&lt;p&gt;Stay tuned!&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Recommendations from a philosophical view</title>
      <link>http://thesis.ljungblad.nu/2012/02/07/philosophy_of_recommendations</link>
      <pubDate>Tue, 07 Feb 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/02/07/philosophy_of_recommendations</guid>
      <description>&lt;p&gt;Quite some time ago I came across a &lt;span class=&quot;caps&quot;&gt;TED&lt;/span&gt; talk about &lt;a href=&quot;http://blog.ted.com/2011/05/02/beware-online-filter-bubbles-eli-pariser-on-ted-com/&quot;&gt;filter bubbles&lt;/a&gt; which emphasize the risk of search engines filtering content which suite your particular taste. Especially how this filtering is narrowing our worldview and, in the long term, how it may affect democracy. The talk is worth watching and relates clearly to recommendation engines. In fact, there exists a debate about what is personalised search and personalised recommendations. Many argue that it is all the same, and that search is irrelevant these days. Personally I believe the difference in use is what makes the distinction. In &lt;em&gt;search&lt;/em&gt; I actively look for material that I wish to find, whereas for &lt;em&gt;recommendations&lt;/em&gt; I&amp;#8217;m exposed (un)willingly to interesting content.&lt;/p&gt;
&lt;p&gt;The New York Times article &lt;a href=&quot;http://www.nytimes.com/2008/11/23/magazine/23Netflix-t.html?_r=1&amp;amp;pagewanted=all&quot;&gt;If you liked this, you&amp;#8217;re sure to love that&lt;/a&gt; highlight another perspective of recommendations: that of culture.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[Prof. Pattie Maes] notes that there’s something slightly antisocial — “narrow-minded” — about hyperpersonalized recommendation systems. Sure, it’s good to have a computer find more of what you already like. But culture isn’t experienced in solitude. We also consume shows and movies and music as a way of participating in society. That social need can override the question of whether or not we’ll like the movie.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Both the filter bubble and hyperpersonalisation can probably be minimised by introducing some randomness, or negating the result (looking for contradicting views). The latter being more algorithmically challenging. However, that will also impact your trust in the recommendations provided, potentially causing you to ignore them completely. And that isn&amp;#8217;t really what we&amp;#8217;re after&amp;#8230;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>On-line computation cost</title>
      <link>http://thesis.ljungblad.nu/2012/02/06/online_prototype</link>
      <pubDate>Mon, 06 Feb 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/02/06/online_prototype</guid>
      <description>&lt;p&gt;Last Friday I hacked together an experimental on-line recommender in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; to evaluate time spent on computation vs size of datasets. Here are some preliminary (discouraging) results using a local memcache setup and the following configuration:&lt;/p&gt;
&lt;p&gt;Users in memory: 500, Concurrent clients: 10, Ranked list length&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;: 100, Item vector size: 20&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/500_10_10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The script runs for 10 seconds during which time each client spams recommendation requests. Each request is independent of each other and are thus treated separately.&lt;/p&gt;
&lt;p&gt;Increasing the number of users to 5000 with the other variables intact yields the following results:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/5000_10_10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This figure shows a similar distribution to 500 users, hence, it suggests we are not capped by the number of users in memory. The total throughput is around 2700 requests. Next I decrease the ranked list size stored in memory. The average latency remains the same, however, total throughput increases to roughly 6000 requests.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/5000_10_10-50.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And with shorter preference vectors (set to 10) but ranked list length back to 100, the throughput is around 4000 requests.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/5000_10_10-vector-10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m unsure why there is a significant portion of requests taking about 120-140 ms.&lt;/p&gt;
&lt;p&gt;In summary, preference factors and ranked list length becomes important configuration variables for on-line computation. Much can, and needs to, be done to further increase the performance, for example, how the selection of the top K recommendations. For a production system we must get the majority of all requests down to, or below, 100 ms. This should include also updating the context vector.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thoughts on &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;
PHP4 was still the mainstream version when I last hacked stuff using &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;. And obviously a lot have changed since. For starters, &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; has a class system! There are also array functions to do operations equivalent to map and reduce (maybe they were there earlier too, but I didn&amp;#8217;t know). My impression so far is that it is pretty easy to get started with (hey, nothing to compile right), but it feels rather bloated.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; is extensive. There seems to be functions for almost everything. Thus having a browser and &lt;a href=&quot;http://php.net&quot;&gt;php.net&lt;/a&gt; open is essential. On the other hand, keeping the code easy to understand felt like a challenge. With experience this ought to be less of an issue. For example, using arrays as both dictionaries, lists, and tuples quickly made me realise I was reading my own code over and over again to see what was being passed around. Thank you Netbeans for auto-completing my very long variable and function names. :)&lt;/p&gt;
&lt;p&gt;Lastly, I found myself looking for threading capabilities to run multiple clients concurrently. Turns out there is no such thing in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;. Instead I ended up writing a python script to wrap my php script in. Epic fail. Naturally, &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; doesn&amp;#8217;t come from a multi-threaded usage, it relies on whatever webserver to handle each request individually and thereby making it multi-threaded.&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; This is the result of the partial model generated off-line and it is unique for every user.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Load test prototype</title>
      <link>http://thesis.ljungblad.nu/2012/02/03/load_test_prototype</link>
      <pubDate>Fri, 03 Feb 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/02/03/load_test_prototype</guid>
      <description>&lt;p&gt;Spent most of the day yesterday doing a simple prototype of the online component. Most of the logic is in place, and the trick now is to test it under load with a realistic storage configuration. Realistic means MySQL and Memcache. In fact, the most realistic would be to run it alongside some production code and use real load to get accurate measures of throughput and latency. That&amp;#8217;d be real awesome. However, we&amp;#8217;re not there yet, especially as that requires us to generate recommendation models for at least a subset of the users.&lt;/p&gt;
&lt;p&gt;What struck me, again, yesterday is how we always lack small easy-to-use tools for generating load. &lt;a href=&quot;http://stream.nicholasrutherford.com/&quot;&gt;Nick&lt;/a&gt; and I faced a similar problem when building our &lt;a href=&quot;https://github.com/nruth/gaoler/&quot;&gt;distributed lock service&lt;/a&gt; and, especially Nick, considered building his own. Why is it that these tools rarely are part of our toolboxes? Sure, there are tools for load-testing, but too often they are clunky and overly sophisticated (JMeter and Tsung to name two). &lt;a href=&quot;https://github.com/basho/basho_bench&quot;&gt;Basho_bench&lt;/a&gt; is one of the better I&amp;#8217;ve seen so far. Set-up is relatively small and you could make it work with &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; interfaces quite easily&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;What am I missing? &lt;a href=&quot;mailto:marcus@ljungblad.nu&quot;&gt;Let me know&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; It is primarily targeted at Erlang applications and was initially written to test the &lt;a href=&quot;http://basho.com/products/riak-overview/&quot;&gt;Riak&lt;/a&gt; database.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Reducing dimensions of the problem</title>
      <link>http://thesis.ljungblad.nu/2012/02/02/reducing_dimensions</link>
      <pubDate>Thu, 02 Feb 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/02/02/reducing_dimensions</guid>
      <description>&lt;p&gt;Yesterday we, Toni and I, went for a meeting at Telefonica&amp;#8217;s offices to brainstorm about possible system solutions for building personalised video recommendations. Together with two system&amp;#8217;s researchers and two algorithm experts we banged our heads at the problem.&lt;/p&gt;
&lt;p&gt;The problem, based on the current dataset, can be summarized as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given 40M videos and 13M users, recommend a personalised set (of length &lt;em&gt;k&lt;/em&gt;) of videos using contextual information which the user may&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; like.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are three parts to highlight here:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Each video is described by a vector of, for example, 20 factors, but can be many more. Hence, the 40M videos is represented by a 40Mx20 dense matrix. Let&amp;#8217;s say each factor can be described by 4 bytes (an int), then this matrix is roughly 3 Gb of data.&lt;/li&gt;
	&lt;li&gt;User preferences are also described by a vector, i.e also a rather large matrix. While the number of videos can be reduced, for example, by cutting the long-tail, the users cannot. In fact, the number of users is expected to grow significantly as Tuenti is expanding into new markets.&lt;/li&gt;
	&lt;li&gt;Contextual information are things like browsing history, the last video viewed, browser settings, weather information, time of day, and whatever else you can think of. This too is represented by a vector and may change on every user action.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Some questions which arise from this are:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;How large sample of the videos can we use?&lt;/li&gt;
	&lt;li&gt;How do we select the videos?&lt;/li&gt;
	&lt;li&gt;How many factors describing the videos / users can we use?&lt;/li&gt;
	&lt;li&gt;How fast can we serve a recommendation request? (The time to load a page shouldn&amp;#8217;t exceed 200 ms)&lt;/li&gt;
	&lt;li&gt;What time budget for each computation (offline and online) do we have / can we allocate?&lt;/li&gt;
	&lt;li&gt;If a request cannot be served (in time), what fault-tolerance or fallback mechanisms do we use?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The algorithms we&amp;#8217;re looking at uses matrix factorisation to compute a relevance matrix. One approach, as discussed in a previous post, is to split the recommendation computation in two parts. One off-line component which calculates a ranked list for each user, but excludes the contextual information. The second part is done on-line and here the contextual information is applied to the ranked list (by calculating the inner product of the two vectors).&lt;/p&gt;
&lt;p&gt;Now, in order to reduce the dimensions of this problem, my next task is to estimate how much contextual information we can use and what size of the ranked list we can store based on current peak-load traffic and beyond.&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; &lt;code&gt;s/may/will/g&lt;/code&gt; depending on your confidence in the algorithm / philosophical view.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Usage analysis</title>
      <link>http://thesis.ljungblad.nu/2012/01/31/usage_analysis</link>
      <pubDate>Tue, 31 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/31/usage_analysis</guid>
      <description>&lt;p&gt;Moving on from the code analysis that I did yesterday in order to understand the different systems and what they are made up of, I continued today with investigating their usage.&lt;/p&gt;
&lt;p&gt;There are currently three recommendation systems in place at Tuenti: Friends, Places, and Videos. The former two have been around for a while, whereas Videos launched more recently. This, if nowhere else, can be seen in the code and the code practices used. There is currently no way of measuring whether a user uses the video recommendations, thus, tomorrow I&amp;#8217;ll try to set that up.&lt;/p&gt;
&lt;p&gt;I wont share any specific numbers yet (hopefully I can do that later). But overall, it&amp;#8217;s been fun playing around with Hive and MapReduce. On a huge codebase it is obivously easy to get lost, and that happened more than once. Initially I didn&amp;#8217;t think there were any statistics at all for Places. It turned out, once I found where I wanted to add the data collection marker, that it was already there. However, it stored the values in another datastore which wasn&amp;#8217;t documented. Do&amp;#8217;h!&lt;/p&gt;
&lt;p&gt;Waiting for last MapReduce job to complete, then &lt;em&gt;ir a de casa&lt;/em&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>A set of requirements for a recommendation framework</title>
      <link>http://thesis.ljungblad.nu/2012/01/30/a_set_of_requirements</link>
      <pubDate>Mon, 30 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/30/a_set_of_requirements</guid>
      <description>&lt;p&gt;&lt;strong&gt;Functional&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;recommend multiple types of content with different characteristics
	&lt;ul&gt;
		&lt;li&gt;videos&lt;/li&gt;
		&lt;li&gt;albums&lt;/li&gt;
		&lt;li&gt;friends&lt;/li&gt;
		&lt;li&gt;games&lt;/li&gt;
		&lt;li&gt;(essentially this means supporting several recommendation algorithms)&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;use implicit feedback data to calculate recommendations
	&lt;ul&gt;
		&lt;li&gt;views by users, click-through&lt;/li&gt;
		&lt;li&gt;support multiple collection points&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;use explicit feedback data
	&lt;ul&gt;
		&lt;li&gt;ratings by a user&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;record contextual information and use it instantenously to update a set of recommendations&lt;/li&gt;
	&lt;li&gt;generate sets of recommendations for specific types and mixed sets&lt;/li&gt;
	&lt;li&gt;be able to use data of different types to generate a specific type&lt;/li&gt;
	&lt;li&gt;support post-processing filters on recommended sets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Non-functional&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;scale to millions of users&lt;/li&gt;
	&lt;li&gt;support peak hours during which activity is significantly higher&lt;/li&gt;
	&lt;li&gt;degrade gracefully if service is limited / unavailable&lt;/li&gt;
	&lt;li&gt;easy to add and deploy new sets of recommendations&lt;/li&gt;
	&lt;li&gt;make use of contextual information in realtime to update recommendations&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Architecting Recommendation Systems for Web-Scale Data</title>
      <link>http://thesis.ljungblad.nu/2012/01/27/structure_of_a_report</link>
      <pubDate>Fri, 27 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/27/structure_of_a_report</guid>
      <description>&lt;p&gt;To evaluate the current thesis proposal I challenged my &lt;a href=&quot;http://lalith.in&quot;&gt;&lt;span class=&quot;caps&quot;&gt;EMDC&lt;/span&gt; colleague Lalith&lt;/a&gt; (who is doing some awesome work with wireless networks at T-Labs in Berlin) with the following question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let&amp;#8217;s hypothetically say the name of my thesis is &amp;#8220;Architecting Recommendation Systems for Web-Scale Data&amp;#8221;. What would you expect to read in it?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, as it turns out his answer, although significanly shorter, matched the following, highly tentative, outline of a report quite well. I&amp;#8217;ve updated it a bit to include Lalith&amp;#8217;s feedback. Now I should verify this with my supervisor at &lt;span class=&quot;caps&quot;&gt;UPC&lt;/span&gt; too.&lt;/p&gt;
&lt;h1&gt;Introduction&lt;/h1&gt;
&lt;ul&gt;
	&lt;li&gt;recommendations for personalisation and increased interaction&lt;/li&gt;
	&lt;li&gt;problem with scale, optimizing algorithms or sampling the data&lt;/li&gt;
	&lt;li&gt;little systems research on collaborative filtering and recommender systems (mostly on algorithms)&lt;/li&gt;
	&lt;li&gt;building a recommendation system which serves millions of users&lt;/li&gt;
	&lt;li&gt;Supporting a range of content: videos, games, photos, albums, friends, places, pages&lt;/li&gt;
	&lt;li&gt;main contributions:
	&lt;ul&gt;
		&lt;li&gt;a system which supports several content types&lt;/li&gt;
		&lt;li&gt;able to update according to recent contextual information&lt;/li&gt;
		&lt;li&gt;evaluation on big data sets&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Background&lt;/h1&gt;
&lt;p&gt;Definitions&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;web-scale data&lt;/li&gt;
	&lt;li&gt;collaborative filtering
	&lt;ul&gt;
		&lt;li&gt;model based &amp;#8211; common approaches&lt;/li&gt;
		&lt;li&gt;memory based &amp;#8211; common approaches&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Describe current solutions to the growing amount of data&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;it has mostly focused on algorithm enhancement and/or downsizing the data&lt;/li&gt;
	&lt;li&gt;some algorithms are being ported to mapreduce, for example through the mahout project&lt;/li&gt;
	&lt;li&gt;other attempts include graphlab which uses something like a &amp;#8220;bulk asynchrounous processing&amp;#8221; model, but still lacks widespread production use and has limited support for distributed computations&lt;/li&gt;
	&lt;li&gt;biggest published system on recommendation systems is google news personalisation. The algorithms are simplified and system specific to Google&amp;#8217;s infrastructure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Problems / Limitations of existing systems&lt;/p&gt;
&lt;h1&gt;Method&lt;/h1&gt;
&lt;p&gt;Something about the research method(s) used. Big &lt;span class=&quot;caps&quot;&gt;TBD&lt;/span&gt;.&lt;/p&gt;
&lt;h1&gt;System / Architecture&lt;/h1&gt;
&lt;ul&gt;
	&lt;li&gt;Data collection &amp;#8211; capturing user feedback, and using it for online feedback&lt;/li&gt;
	&lt;li&gt;Algorithms for computing recommendation model &amp;#8211; dividing the model in two parts&lt;/li&gt;
	&lt;li&gt;Serving recommendations&lt;/li&gt;
	&lt;li&gt;Updating recommendations based on contextual data from a session, i.e creating relevant recommendations on the most recent user activities.&lt;/li&gt;
	&lt;li&gt;Components needed / Implementation
	&lt;ul&gt;
		&lt;li&gt;offline (non-realtime)&lt;/li&gt;
		&lt;li&gt;online (realtime)&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Details&lt;/h1&gt;
&lt;ul&gt;
	&lt;li&gt;Usage peaks &amp;#8211; degrading quality of service depending on load&lt;/li&gt;
	&lt;li&gt;Blacklisting, i.e removing recommendations that a user deemed irrelevant or has already seen&lt;/li&gt;
	&lt;li&gt;Updating / creating new recommendations on the fly&lt;/li&gt;
	&lt;li&gt;New users / cold start, i.e what to do when there are no previous history from the user&lt;/li&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;HCI&lt;/span&gt; &amp;#8211; How long time does it take to serve a recommendation vs better to change UI to improve effectiveness (&lt;span class=&quot;caps&quot;&gt;TBD&lt;/span&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Evaluation&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Quantitative&lt;/strong&gt;&lt;br /&gt;
Measure existing recommendations and compare with new system&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;accuracy of algorithm (not sure how relevant this is for a systems paper)&lt;/li&gt;
	&lt;li&gt;accuracy vs load&lt;/li&gt;
	&lt;li&gt;serving recommendations (latency / throughput)&lt;/li&gt;
	&lt;li&gt;clicks/interaction&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also check if it is quantatively comparable to any existing systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Qualitative&lt;/strong&gt;&lt;br /&gt;
Architecture&lt;br /&gt;
Flexibility / modularity &lt;br /&gt;
Scalability&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;It will be awesome ;)&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>A day of tutorials and code</title>
      <link>http://thesis.ljungblad.nu/2012/01/25/tutorials_and_code</link>
      <pubDate>Wed, 25 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/25/tutorials_and_code</guid>
      <description>&lt;p&gt;Next step, after getting the gist of recommender systems was to narrow down on the existing systems and practices at Tuenti. Since the company has grown quite rapidly in the last two years, a full suite of training material exists to help introduce engineers to the systems. Despite each tutorial being quite short, it took more or less the entire day to go through the first stuff, check out code, and set-up environment properly.&lt;/p&gt;
&lt;p&gt;Tomorrow I will focus on analysing the existing recommendation systems.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Production recommender systems</title>
      <link>http://thesis.ljungblad.nu/2012/01/24/production_recommender_systems</link>
      <pubDate>Tue, 24 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/24/production_recommender_systems</guid>
      <description>&lt;p&gt;Here&amp;#8217;s a small collection recommender systems in production that I&amp;#8217;ve come across in my background research. It is far from complete and if you know of anyone particularly interesting (especially where the datasets or item churn is extraordinary), please &lt;a href=&quot;mailto:marcus@ljungblad.nu&quot;&gt;drop me an e-mail&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;The developer&amp;#8217;s at &lt;a href=&quot;http://engineering.foursquare.com/2011/03/22/building-a-recommendation-engine-foursquare-style/&quot;&gt;Foursquare made Explore&lt;/a&gt; using some pretty big datasets.&lt;/li&gt;
	&lt;li&gt;At Amazon they&amp;#8217;ve been doing product &lt;a href=&quot;http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=1167344&quot;&gt;item-to-item recommendations&lt;/a&gt; for quite a while. &lt;a href=&quot;http://glinden.blogspot.com&quot;&gt;Greg Linden&lt;/a&gt; is recommendation king over there.&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www2007.org/papers/paper570.pdf&quot;&gt;Google News personalises stories&lt;/a&gt; for you based on similar user&amp;#8217;s click history.&lt;/li&gt;
	&lt;li&gt;The game-changing challenge announced by Netflix stirred up some serious activity in the research community. The &lt;a href=&quot;http://www.netflixprize.com&quot;&gt;prize&lt;/a&gt; totaled $1M dollars.&lt;/li&gt;
	&lt;li&gt;Drupal, popular &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt; system, provides a &lt;a href=&quot;http://drupal.org/project/recommender&quot;&gt;recommendation &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;&lt;/a&gt;.&lt;/li&gt;
	&lt;li&gt;LastFM&amp;#8217;s &amp;#8220;Audioscrobbler&amp;#8221; is based entirely on recommendations, but instead of improving the algorithms, &lt;a href=&quot;http://en.wikipedia.org/wiki/Last.fm&quot;&gt;LastFM focused on extracting really good data from the users&lt;/a&gt;. That turned out quite well too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then I&amp;#8217;ve also seen Digg, StumbleUpon, Movielens, Facebook (duh), and many more mentioned, but have no links on how they work.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Mahout vs GraphLab</title>
      <link>http://thesis.ljungblad.nu/2012/01/23/mahout_vs_graphlab</link>
      <pubDate>Mon, 23 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/23/mahout_vs_graphlab</guid>
      <description>&lt;h1&gt;Mahout&lt;/h1&gt;
&lt;p&gt;Is &lt;a href=&quot;http://mahout.apache.org&quot;&gt;a framework for machine learning&lt;/a&gt; and part of the Apache Foundation. A sub-framework of Mahout is Taste used specifically for collaborative filtering.&lt;/p&gt;
&lt;p&gt;The Taste framework comes in two tastes (pun intended):&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;Online&lt;/strong&gt; where recommendations are computed on demand, typically on smaller datasets. This version is easily integrated in existing Java applications either by using on of the existing Recommender algorithms. Online computations are done in memory (as long as they fit) these can be updated more frequently by, for example, pushing new .csv files, or using data from a &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; database.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Offline&lt;/strong&gt; which utilise &lt;a href=&quot;http://hadoop.apache.org&quot;&gt;Apache Hadoop&lt;/a&gt; to achieve scalability. Mahout points out, however, that &lt;a href=&quot;http://tdunning.blogspot.com/2009/01/real-time-decision-making-using-map.html&quot;&gt;map-reduce tasks doesn&amp;#8217;t logically fit all types of algorithms&lt;/a&gt; and are hence exploring alternative distribution methods too.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;a href=&quot;https://cwiki.apache.org/MAHOUT/recommender-first-timer-faq.html&quot;&gt;recommender beginner&amp;#8217;s wiki&lt;/a&gt; points out that datasets containing up to 100M user-item ratings should be computable online using a decent server.&lt;/p&gt;
&lt;p&gt;Not all algorithms provided by Taste are available as Hadoop implementations. There is an &lt;a href=&quot;https://cwiki.apache.org/MAHOUT/collaborative-filtering-with-als-wr.html&quot;&gt;iterative algorithm for matrix factorization&lt;/a&gt; using Alternating Least Squares. Iterative algorithms incur significant overhead when written as MapReduce jobs in Hadoop (a better way could be to model the computation using bulk synchronous processing, like Pregel).&lt;/p&gt;
&lt;p&gt;Building a system which combines Mahout&amp;#8217;s offline and online capabilities seems yet to be done. Basically since you want your online computations to be O(1) I&amp;#8217;m not sure that Mahout is a good fit. It might be easier to do online updates on data on the side, and possibly use Mahout for the offline computations.&lt;/p&gt;
&lt;p&gt;Decent introductions to Mahout can be found &lt;a href=&quot;http://www.ibm.com/developerworks/java/library/j-mahout/&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;http://www.searchworkings.org/blog?p_p_id=141_INSTANCE_7hQd&amp;amp;p_p_lifecycle=0&amp;amp;p_p_state=normal&amp;amp;p_p_mode=view&amp;amp;p_p_col_id=column-2&amp;amp;p_p_col_pos=1&amp;amp;p_p_col_count=3&amp;amp;p_r_p_564233524_tag=mahout&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This page has information about &lt;a href=&quot;https://cwiki.apache.org/MAHOUT/recommender-documentation.html&quot;&gt;the recommender architecture&lt;/a&gt; and how to build your own recommenders. The architecture does not provide an intuitive explanation for how the collaborative framework connects to Hadoop. Based on a brief tour &lt;a href=&quot;https://svn.apache.org/repos/asf/mahout/trunk/core/src/main/java/org/apache/mahout/common/AbstractJob.java&quot;&gt;in the source code&lt;/a&gt; it looks like Mahout provides a &amp;#8220;Hadoop Job Factory&amp;#8221; which generates and submits map- and reduce tasks (aka jobs) to your Hadoop cluster.&lt;/p&gt;
&lt;p&gt;Mahout has also been shown to run on &lt;a href=&quot;https://cwiki.apache.org/confluence/display/MAHOUT/Mahout+on+Elastic+MapReduce&quot;&gt;&lt;span class=&quot;caps&quot;&gt;AWS&lt;/span&gt; Elastic MapReduce&lt;/a&gt; which, given the readme, does not seem like a trivial task.&lt;/p&gt;
&lt;p&gt;Foursquare provides a &lt;a href=&quot;http://engineering.foursquare.com/2011/03/22/building-a-recommendation-engine-foursquare-style/&quot;&gt;pretty interesting use-case on Mahout&lt;/a&gt; with extremely large datasets, and also emphasizes the fact that Mahout is geared towards industry.&lt;/p&gt;
&lt;h1&gt;Graphlab&lt;/h1&gt;
&lt;p&gt;On the other hand, the &lt;a href=&quot;http://graphlab.org/&quot;&gt;Graphlab project&lt;/a&gt; takes a quite different approach to parallel collaborative filtering (more broadly, machine learning), and is primarily used by academic institutions.&lt;/p&gt;
&lt;p&gt;Graphlab jobs operate on a graph data structure much similar to Google&amp;#8217;s system Pregel. Computation is defined through an update-function which operates on one vertex of the graph at the time. During an update call, new update requests can be scheduled with other vertices of the graph. A central scheduler delegates vertices for processing. For a good example, see the &lt;a href=&quot;http://graphlab.org/doxygen/html/pagerank_example.html&quot;&gt;Graphlab implementation of Pagerank&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Contrary to Hadoop, Graphlab is built for multi-core parallelism, although there is on-going work in making it easier to user in a distributed setup. It also seem to lack mechanisms for fault-tolerance (for example, map or reduce tasks are restarted by the master if they fail to complete).&lt;/p&gt;
&lt;p&gt;However, Graphlab boasts that &amp;#8220;implementing efficient and provably correct parallel machine algorithms&amp;#8221; is easier when compared to MapReduce. Especially since computation &lt;a href=&quot;http://graphlab.org/abstractiononly.pdf&quot;&gt;is not required to be transformed into an embarrassingly parallel form&lt;/a&gt;. It is different from Pregel in the sense that communication between vertices is implicit, and that computation is asynchronous. The latter implies that computation on a vertex will happen on the most recent available data. By ensuring that all computations are sequentially consistent, the end result data will eventually also be consistent, programs becomes easier to debug, and complexity of parallelism is reduced.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Mahout looks like a more polished product, especially as it relies on Hadoop for scalability and distribution. Its computational model may, however, be constrained just because of the same prerequisite. It is, hence, here Graphlab excells since it is built ground up for iterative algorithms such as those used in collaborative filtering. On the downside, Graphlab lacks a production-ready distribution framework.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Head-banging</title>
      <link>http://thesis.ljungblad.nu/2012/01/20/head_banging</link>
      <pubDate>Fri, 20 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/20/head_banging</guid>
      <description>&lt;p&gt;First whole week at Tuenti completed. Some progress, and a bunch of questions. Here&amp;#8217;s the short crackdown:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Acquired an understanding of the problem with recommendations, why it is useful, where it is used, who the big players are, and how it has evolved over the years.&lt;/li&gt;
	&lt;li&gt;Learned about matrix factorization techniques for predicting recommendations. Although I&amp;#8217;m not sure I fully understand how it is done, I get the gist. Probably wouldn&amp;#8217;t attempt to implement one of the more complicated algorithms on my own yet.&lt;/li&gt;
	&lt;li&gt;Tweaked and &lt;a href=&quot;http://thesis.ljungblad.nu/2012/01/17/alternating_least_squares&quot;&gt;refactored some code&lt;/a&gt; which does simple matrix factorization on very small datasets, and in a sequential manner. Check the &lt;a href=&quot;https://gist.github.com/1626941&quot;&gt;refactored code on Github&lt;/a&gt;.&lt;/li&gt;
	&lt;li&gt;Read numerous papers about algorithms (many of which I don&amp;#8217;t understand, but able to classify).&lt;/li&gt;
	&lt;li&gt;Read the few papers I could find on recommendation systems architecture. Google News personalisation being the most prominent one.&lt;/li&gt;
	&lt;li&gt;Studied the &lt;a href=&quot;https://cwiki.apache.org/MAHOUT/mahout-wiki.html&quot;&gt;Mahout&lt;/a&gt; architecture; a machine learning framework which is able to utilize Hadoop for larger datasets. It works offline only (although Taste, the recommendation framework, is pluggable for online recommendations too) and does not support model-based algorithms yet, afaik.&lt;/li&gt;
	&lt;li&gt;Discovered that there isn&amp;#8217;t a whole lot of research, papers, or blogposts on the actual implementations of recommendation systems. &lt;a href=&quot;http://thesis.ljungblad.nu/2012/01/19/motivating_my_topic&quot;&gt;Good for me&lt;/a&gt;, I guess.&lt;/li&gt;
	&lt;li&gt;Began studying Tuenti&amp;#8217;s internal architecture based on technical specifications and requirement documents. Much of it I will never cover here. Next week a colleague is giving me and Toni a walkthrough of the essentials. Will be very interesting as a lot of things here really are at large scale. Things we only studied in papers before.&lt;/li&gt;
	&lt;li&gt;Rewrote my thesis position paper based on this week&amp;#8217;s findings. As soon as the Tuenti architecture background is complete I should be able to finalise it and send it for a final review. My &lt;span class=&quot;caps&quot;&gt;UPC&lt;/span&gt; supervisor isn&amp;#8217;t responding to e-mails at the moment (and hasn&amp;#8217;t for a week) which is an issue though.&lt;/li&gt;
	&lt;li&gt;Got some rough ideas on a possible system design if I could do it entirely as I want. That&amp;#8217;s obviously neither a good idea, nor feasible. But sketching is always fun.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;#8217;s been a lot this week. Although I still haven&amp;#8217;t been able to exactly specify the topic and the work, I&amp;#8217;m getting more confident that we&amp;#8217;ll find something. The best part is that basically whatever I look at is really interesting. Perhaps with an exception for some of the complicated math algorithms.&lt;/p&gt;
&lt;p&gt;Now pizza.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Survey paper on CF recommendation algorithms</title>
      <link>http://thesis.ljungblad.nu/2012/01/19/survey_on_cf_algorithms</link>
      <pubDate>Thu, 19 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/19/survey_on_cf_algorithms</guid>
      <description>&lt;p&gt;Found this paper titled &lt;a href=&quot;http://www.hindawi.com/journals/aai/2009/421425/&quot;&gt;A Survey of Collaborative Filtering Techniques&lt;/a&gt; from 2009. It is more recent than the previous survey paper I found and contains some useful references to the challenges with CF techniques.&lt;/p&gt;
&lt;p&gt;One particular challenge with recommendation algorithms is to scale them to tens of millions of users and millions of items. Most research predating the &lt;a href=&quot;http://www.netflixprize.com/&quot;&gt;Netflix Prize&lt;/a&gt; considers &amp;#8220;large-scale&amp;#8221; to be several orders of magnitude smaller than millions. Even the Netflix data is small in comparison to the datasets used at Google News or Amazon. Essentially &lt;code&gt;O(n)&lt;/code&gt; is too slow for those numbers.&lt;/p&gt;
&lt;p&gt;Several techniques have been proposed to address the scalability issue. In particular:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Doing matrix factorization once and updating it online (specifically Singular Value Decomposition) using projections.&lt;/li&gt;
	&lt;li&gt;Using Hadoop MapReduce. While some algorithms can be parallelised and made to support MapReduce, it doesn&amp;#8217;t solve the freshness of the data if it changes quickly. Something web data have a tendency of doing.&lt;/li&gt;
	&lt;li&gt;Intermediate approaches have also been proposed. For example, instead of computing the top K recommendations on the entire user database, the users are first clustered (as in Google News), and recommendations are calculated on the fly using these smaller clusters.&lt;/li&gt;
	&lt;li&gt;The above paper mentions Pearson correlation (memory based algorithm) as a viable alternative to scale. I&amp;#8217;m not convinced, however. If the data is too large to store in memory it will be too slow as reads have to be made from disk instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I haven&amp;#8217;t read the entire survey, but it seems to be covering quite a few of the collaborative filtering techniques that I&amp;#8217;ve seen mentioned in several other papers.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Summary of "Google News Personalization Scalable Online Collaborative Filtering"</title>
      <link>http://thesis.ljungblad.nu/2012/01/19/summary_google_news_personalisation</link>
      <pubDate>Thu, 19 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/19/summary_google_news_personalisation</guid>
      <description>&lt;p&gt;The authors describe three algorithms for content-agnostic recommendations and the system architecture employed to serve personalised news on &lt;a href=&quot;http://news.google.com&quot;&gt;Google News&lt;/a&gt;. Their contribution is distinct from earlier CF research in two ways: the massive scale and high item (news) churn.&lt;/p&gt;
&lt;p&gt;CF algorithms, as mentioned in a previous post, can be categorised in two areas: memory-based and model-based. The former is significantly hard to deploy on massive item-sets since (surpise) everything needs to be kept in memory. This quickly becomes unfeasible. In Google News this is a an online covisitation algortihm which only updates the affected news items, and thus does not need to be maintained in memory. Two other model-based algorithms, both calculating clusters, are computed offline.&lt;/p&gt;
&lt;p&gt;The engineers divided the system in three parts:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;An offline part&lt;/strong&gt; which is basically MapReduce jobs running periodically to compute user clusters based on their click history.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;An online update part&lt;/strong&gt; that continuously updates the statistics when a user clicks a news item.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;An online retrieval part&lt;/strong&gt; which fetches and computes news recommendations from the statistics and clusters stored.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The system is split into five components:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;Front-ends&lt;/strong&gt; which listens to registered user activity. The front-end passes the data on to either of the two following components.&lt;/li&gt;
	&lt;li&gt;The &lt;strong&gt;Statistics engine&lt;/strong&gt; updates the user clusters and story items based on the clicks received. All information is stored in one of two tables: a user table and a story table.&lt;/li&gt;
	&lt;li&gt;The third server is the &lt;strong&gt;prediction engine&lt;/strong&gt; which, given a set of user options (for example: language used, regional settings, and so on) and a few news items from these settings, computes a set of ranked stories. The top-K ones are presented to the user. The prediction engine fetches information from both tables and caches them for an &amp;#8220;appropriate&amp;#8221; time-window.&lt;/li&gt;
	&lt;li&gt;The &lt;strong&gt;BigTable tables&lt;/strong&gt; which stores user and story statistics.
	&lt;ol&gt;
		&lt;li&gt;The users are indexed by id and contains two columns: a list of clusters the user belongs to, and click history.&lt;/li&gt;
		&lt;li&gt;The story table, indexed by story-id, contains how many times a story was clicked from users in each cluster, and how many times the story was visited along with another story&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
	&lt;/ol&gt;&lt;/li&gt;
	&lt;li&gt;The &lt;strong&gt;offline component&lt;/strong&gt; operates on a &amp;#8220;few months&amp;#8221; of user data to create user clusters using the two model-based algorithms.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As components are split, the system can continue to serve personalised requests even if, for example, the statistics engine breaks. Multiple instances of each component increases the availability.&lt;/p&gt;
&lt;p&gt;Finally, the system serves prediction requests in less than 100 ms. There are also evaluation of the prediction accuracy, but that is not as important now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reference:&lt;/strong&gt;&lt;br /&gt;
Das, Abhinandan S., Mayur Datar, Ashutosh Garg, and Shyam Rajaram. “Google news personalization: scalable online collaborative filtering.” &lt;i&gt;In Proceedings of the 16th international conference on World Wide Web&lt;/i&gt;, 271–280. &lt;span class=&quot;caps&quot;&gt;WWW&lt;/span&gt;  ’07. New York, NY, &lt;span class=&quot;caps&quot;&gt;USA&lt;/span&gt;: &lt;span class=&quot;caps&quot;&gt;ACM&lt;/span&gt;, 2007. http://doi.acm.org/10.1145/1242572.1242610.&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; A story is covisited if a user clicks two stories after each other within a specified time-window.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Motivating my thesis topic</title>
      <link>http://thesis.ljungblad.nu/2012/01/19/motivating_my_topic</link>
      <pubDate>Thu, 19 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/19/motivating_my_topic</guid>
      <description>&lt;p&gt;Found the following quote in another survey paper on &lt;a href=&quot;http://www.prem-melville.com/publications/recommender-systems-eml2010.pdf&quot;&gt;Recommender systems&lt;/a&gt; from 2010.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The architecture of recommender systems and their evaluation on real-world problems is an active area of research.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;\o/&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Summary of "A case for distributed recommender system architecture"</title>
      <link>http://thesis.ljungblad.nu/2012/01/18/summary_distributed_recommender_systems</link>
      <pubDate>Wed, 18 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/18/summary_distributed_recommender_systems</guid>
      <description>&lt;p&gt;&lt;i&gt;This paper makes it to my top-ten list of worst research papers ever.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;The authors, correctly, identifies that historically recommender systems are made sequential, have difficulties scaling, and are often built for specific purposes. With this outset, they propose four architectural techniques: network centric, client-server, layer, and component patterns, which magically will solve all issues of recommender systems.&lt;/p&gt;
&lt;p&gt;While the abstract and introduction starts of fine, until you check the references that it uses to support some of the claims the authors are making, the solution proposed offers no novelty, implementation, or evaluation. It is purely hypothetical. The authors seem to have a superficial understanding of recommendation algorithms which are barely touched upon, let alone described, in the paper. Moreover, the claims made in the introduction are based on recommendation research from the early 90s and the paper was published in 2010.&lt;/p&gt;
&lt;p&gt;Unfortunately, nowhere is it explained how the proposed patterns are distributing the load of commercial-scale (hundreds of thousands or more entries) recommendation datasets. And they, likely, haven&amp;#8217;t heard of &lt;a href=&quot;http://hadoop.apache.org&quot;&gt;Hadoop&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On the upside of things, there seem to be plenty of room for actually providing something substantial in the field of scalable and fault-tolerant recommender systems.&lt;/p&gt;
&lt;p&gt;Next paper: Amazon&amp;#8217;s item-to-item recommendations.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>More Matrix Factorization</title>
      <link>http://thesis.ljungblad.nu/2012/01/17/alternating_least_squares</link>
      <pubDate>Tue, 17 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/17/alternating_least_squares</guid>
      <description>&lt;p&gt;In order to better understand matrix factorization&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; I wanted to experiment with it in code. I find code much easier to understand than the Greek symbols in papers. Plus, you can tinker with it.&lt;/p&gt;
&lt;p&gt;A little digging gave me &lt;a href=&quot;http://www.quuxlabs.com/blog/2010/09/matrix-factorization-a-simple-tutorial-and-implementation-in-python/&quot;&gt;Albert Au Yeung&amp;#8217;s matrix factorization tutorial&lt;/a&gt; with some python code. His code, to me, wasn&amp;#8217;t very easily understood, and therefore, after some refactoring this is what I came up with. It can surely be made even easier to understand. For more details of the maths, read his post.&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/1626941.js&quot;&gt; &lt;/script&gt;&lt;p&gt;The code assumes users are rating items. When the rating is defined as &lt;code&gt;0&lt;/code&gt; in the input matrix, the user has not yet rated the item. The goal, hence, is to predict those values by discovering to matrices, which product, approximates the missing ratings. Obviously, the approximation is based on the already existing ratings. Thus, when calculating the mean squared error, this is done by comparing already existing ratings against predicted ratings. When the approximation error is small enough, or when &lt;code&gt;MaxSteps&lt;/code&gt; is reached, we quit and take the dot product of the two resulting matrices to yield the predicted ratings for all users and movies.&lt;/p&gt;
&lt;p&gt;It is not intuitive where the &lt;code&gt;InitialUserFeatures&lt;/code&gt; and &lt;code&gt;InitialMovieFeatures&lt;/code&gt; come from. In collaborative filtering algorithms, it is assumed that each user has some initial preferences, for example, based on their previous actions. However, in a new system where no previous data exists, i.e when bootstrapping, this can be merely an educated guess or made up by implicit data. In the example above each user&amp;#8217;s preferences are therefore randomised for the &lt;code&gt;NumberOfLatentFeatures&lt;/code&gt; we are trying to uncover.&lt;/p&gt;
&lt;p&gt;The result of one example run is: &lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
[[ 4.98400885  2.96534946  3.77717477  0.99965545]&lt;br /&gt;
 [ 3.97376149  2.37641209  3.21611904  0.99749797]&lt;br /&gt;
 [ 1.03827929  0.90545444  5.63804813  4.96223337]&lt;br /&gt;
 [ 0.9813382   0.81234711  4.59620317  3.97213023]&lt;br /&gt;
 [ 1.49546775  1.11543839  4.93859812  4.0289544 ]]&lt;br /&gt;
[Finished]&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;If the ratings are from 1-5, it is not very useful that the algorithm estimates the rating 5.64 in one particular case. Since a predicted value may exceed 5, but never be less than 0, it would be good to add some constraints on the final predicted values.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m considering rewriting the code to suite a much larger dataset (100k+ users) next.&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; Matrix Factorization is probably part of a math&amp;#8217;s course we never had as Software Engineering students at &lt;span class=&quot;caps&quot;&gt;ITU&lt;/span&gt;. Wish I had more maths in undergrad.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Time Computing vs Accuracy</title>
      <link>http://thesis.ljungblad.nu/2012/01/16/time_computing_vs_accuracy</link>
      <pubDate>Mon, 16 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/16/time_computing_vs_accuracy</guid>
      <description>&lt;p&gt;Algorithm suggested at the moment is using Alternating Least Squares (&lt;span class=&quot;caps&quot;&gt;ALS&lt;/span&gt;) to optimise the result. &lt;span class=&quot;caps&quot;&gt;ALS&lt;/span&gt; is easy to parallelise, but may not be as accurate as &lt;a href=&quot;http://sifter.org/~simon/journal/20061211.html&quot;&gt;Stochastic gradient descent&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thus, one area to explore is how can computation time increase accuracy? Or, conversely, if we&amp;#8217;re short on time, degrading the accuracy gracefully.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Singular Value Decomposition</title>
      <link>http://thesis.ljungblad.nu/2012/01/16/singular_value_decomposition</link>
      <pubDate>Mon, 16 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/16/singular_value_decomposition</guid>
      <description>&lt;p&gt;While reading up on how Singular Value Decomposition (&lt;span class=&quot;caps&quot;&gt;SVD&lt;/span&gt;) works I found this quote by &lt;a href=&quot;http://sifter.org/~simon/journal/20061211.html&quot;&gt;Simon Funk&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;In today&amp;#8217;s foray, that model is called singular value decomposition, which is just a fancy way of saying what I&amp;#8217;ve already eluded to above.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nice to hear other people shudder about how we try to over-complicate a lot of things, especially in research and marketing departments.&lt;/p&gt;
&lt;p&gt;As far as I understand, the intuition behind &lt;span class=&quot;caps&quot;&gt;SVD&lt;/span&gt; (as applied to estimating ratings) is that you have matrix and you want to find two matrices that, when multiplied, predict the actual matrix with a minimal error of the approximation. This can be done in iterations to improve the accuracy of the prediction, and the nice thing about &lt;span class=&quot;caps&quot;&gt;SVD&lt;/span&gt; is that it will automagically converge on the most optimal solution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alternating Least Squares&lt;/strong&gt;&lt;br /&gt;
However, a complication arises when the matrix you are trying to decompose is not complete. Or, in other words, when there are some fields in the matrix which are empty or undefined &lt;span class=&quot;caps&quot;&gt;SVD&lt;/span&gt; is insufficient for finding the composing matrices. In this case Alternating Least Squares (&lt;span class=&quot;caps&quot;&gt;ALS&lt;/span&gt;) is the way to go. More to come about this.&lt;/p&gt;
&lt;p&gt;Also, here is another remarkable quote I found in a paper from Zhou et al.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;We have found parallel Matlab to be flexible and efficient, and very straightforward to program. Thus, from our experience, it seems to be a strong candidate for widespread, easily scalable parallel/distributed computing [compared to Hadoop and MapReduce].&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some more references:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Zhou, Yunhong, Dennis Wilkinson, Robert Schreiber, and Rong Pan. “Large-Scale Parallel Collaborative Filtering for the Netflix Prize.” &lt;span class=&quot;caps&quot;&gt;PROC&lt;/span&gt;. 4TH INT’L &lt;span class=&quot;caps&quot;&gt;CONF&lt;/span&gt;. &lt;span class=&quot;caps&quot;&gt;ALGORITHMIC&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;ASPECTS&lt;/span&gt; IN &lt;span class=&quot;caps&quot;&gt;INFORMATION&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;MANAGEMENT&lt;/span&gt;, &lt;span class=&quot;caps&quot;&gt;LNCS&lt;/span&gt; 5034 (2008): 337&amp;#8212;348.&lt;/li&gt;
	&lt;li&gt;Koren, Y., R. Bell, and C. Volinsky. “Matrix Factorization Techniques for Recommender Systems.” Computer 42, no. 8 (August 2009): 30-37.&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.puffinwarellc.com/index.php/news-and-articles/articles/30-singular-value-decomposition-tutorial.html?start=1&quot;&gt;How does &lt;span class=&quot;caps&quot;&gt;SVD&lt;/span&gt; work&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Summary of Toward the Next Generation of Recommender Systems</title>
      <link>http://thesis.ljungblad.nu/2012/01/13/survey_summary</link>
      <pubDate>Fri, 13 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/13/survey_summary</guid>
      <description>&lt;p&gt;&lt;a href=&quot;http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.107.2790&quot;&gt;The paper surveys the recommendation research area from around the mid-90s to around 2005&lt;/a&gt;, when the paper is published. The main contribution is a table classifying existing deployments and research in content-based, collaborative, and hybrid recommendation systems.&lt;/p&gt;
&lt;p&gt;The general algorithm may be described as RelevanceOfItem = User x Item, or utility(user,item). Due to the size of this set, it is usually not computed for the whole user space. Instead there are a number of predictions available. These predictions are calculated using either a memory (sometimes called heuristic) method or a model-based method to compute the relevance of items for users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Collaborative Methods&lt;/strong&gt;&lt;br /&gt;
These recommendation systems uses the ratings of other users to produce a relevance set for a particular user. This is done with a user-similarity function which can be defined in several ways. The similarity is usually computed as the distance between two users and this value is used as a weight for the relevance calculation of an item which the user has not yet rated. One technique to find similarity between two users is to look at the items they have both rated previously. However, the calculations should be normalised (see formula 10b in the paper) to account for the fact that different users use, for example, a rating scale differently. 10 doesn&amp;#8217;t always mean 10.&lt;/p&gt;
&lt;p&gt;Two graph-theoretic approaches to collaborative filtering include the Pearson coefficient and the cosine-based approach.&lt;/p&gt;
&lt;p&gt;Calculating user similarities can be expensive and thus one approach is to precompute these values for all users (recomputing them once in a while) and calculating the ratings much more efficiently when the user actually asks for them.&lt;/p&gt;
&lt;p&gt;Predictions can also be made using a model-based technique. This may be probabilistic, for example using clustering or Bayesian networks. Making the model representative is challenging, and clustering may, for example, only limit a user to one single cluster.&lt;/p&gt;
&lt;p&gt;Machine learning techniques have also been proposed to address the nature of evolving data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Issues with collaborative methods&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;New users may have no or very little similarity to existing users. Relates to bootstrapping data. Take generalised sets?&lt;/li&gt;
	&lt;li&gt;New items relies on users rating them. Some weird items may be rated very high but only by a small set of users and thus have less total influence.&lt;/li&gt;
	&lt;li&gt;Sparsity, i.e there is not enough data. Adding context or using more profile data about the users is a way of overcoming this problem. The paper makes a case about using demographic data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are also hybrid versions that can address some of the short-comings in each of the two main methods.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Comments&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;OLAP&lt;/span&gt; &amp;#8211; check the paper Phillipe mentioned in his talk.&lt;/li&gt;
	&lt;li&gt;Bootstrapping &amp;#8211; either make some educated guesses or make sure you have data from the users.&lt;/li&gt;
	&lt;li&gt;Would be fun to hack a small simple recommendation system just to get the gist of it.&lt;/li&gt;
	&lt;li&gt;The paper makes a number of references to scalability issues with recommendation systems but provide no discussion in the paper itself.&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>First day at Tuenti</title>
      <link>http://thesis.ljungblad.nu/2012/01/12/first_day_at_tuenti</link>
      <pubDate>Thu, 12 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/12/first_day_at_tuenti</guid>
      <description>&lt;p&gt;Got impressed.&lt;/p&gt;
&lt;p&gt;Got a workplace.&lt;/p&gt;
&lt;p&gt;Got introduced.&lt;/p&gt;
&lt;p&gt;Forgot everyone&amp;#8217;s names.&lt;/p&gt;
&lt;p&gt;Except Toni (es), my colleague who is an expert on recommendation systems, Tomasz (swe), the Barcelona boss, Albert (es), my supervisor in the product team responsible for the recommendation system development, Einar (swe), also in the team, and Virginia (ar), the very helpful office assistant. I&amp;#8217;ll learn the other names eventually.&lt;/p&gt;
&lt;p&gt;Got hungry.&lt;/p&gt;
&lt;p&gt;Had an exceptionally late lunch by Swedish standards.&lt;/p&gt;
&lt;p&gt;Began reading a survey paper on recommendation systems. More info to come.&lt;/p&gt;
&lt;p&gt;Got impressed.&lt;/p&gt;
&lt;p&gt;Had a product brainstorm meeting. I had no clue about anything.&lt;/p&gt;
&lt;p&gt;Still have no clue.&lt;/p&gt;
&lt;p&gt;Is happy.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Entry 4</title>
      <link>http://thesis.ljungblad.nu/2012/01/07/tired</link>
      <pubDate>Sat, 07 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/07/tired</guid>
      <description>&lt;p&gt;I&amp;#8217;m tired of course work now. Need one of these:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://images.yuku.com/image/jpg/e1f366316ab460078a35a79656022b11c02b1b25_r.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Entry 3</title>
      <link>http://thesis.ljungblad.nu/2012/01/06/facebook_builds_timeline</link>
      <pubDate>Fri, 06 Jan 2012 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2012/01/06/facebook_builds_timeline</guid>
      <description>&lt;p&gt;Facebook built Timeline by &lt;a href=&quot;https://www.facebook.com/notes/facebook-engineering/building-timeline-scaling-up-to-hold-your-life-story/10150468255628920&quot;&gt;recomputing tonnes of data&lt;/a&gt; into a common data format. Aggregators are used to query multiple databases simultaneously. Reminds me of Dremel which Google developed.&lt;/p&gt;
&lt;p&gt;Moving to Barcelona in less than a week. Excited.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Entry 2</title>
      <link>http://thesis.ljungblad.nu/2011/12/25/massive_near_real_time_architectures</link>
      <pubDate>Sun, 25 Dec 2011 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2011/12/25/massive_near_real_time_architectures</guid>
      <description>&lt;p&gt;I found &lt;a href=&quot;http://horovits.wordpress.com/2011/12/19/architecting-massively-scalable-near-real-time-risk-analysis-solutions/&quot;&gt;this post&lt;/a&gt; today on how to architect near real-time systems for risk analysis. The problem seem similar to recommendation engines which uses a lot of history data that rarely change, and only little data which change frequently.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Entry 1</title>
      <link>http://thesis.ljungblad.nu/2011/12/15/first_post</link>
      <pubDate>Thu, 15 Dec 2011 00:00:00 -0800</pubDate>
      <author>marcus@ljungblad.nu (Marcus Ljungblad)</author>
      <guid>http://thesis.ljungblad.nu/2011/12/15/first_post</guid>
      <description>&lt;p&gt;This will be a collection of data, comments, ideas, summaries, links, babbling, and random whatnots which somehow relates to my thesis work at &lt;a href=&quot;http://tuenti.com&quot;&gt;Tuenti&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.hodique.info/lib/exe/fetch.php?hash=e2d00b&amp;amp;media=http%3A%2F%2Fwww.phdcomics.com%2Fcomics%2Farchive%2Fphd040207s.gif&quot; title=&quot;Not there yet&quot; alt=&quot;Not there yet&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Expected end-date: mid-June.&lt;/p&gt;</description>
    </item>
    

  </channel> 
</rss>

