{"id":324,"date":"2009-12-09T11:06:36","date_gmt":"2009-12-09T10:06:36","guid":{"rendered":"http:\/\/blog.jteam.nl\/?p=324"},"modified":"2009-12-09T11:06:36","modified_gmt":"2009-12-09T10:06:36","slug":"mahout-taste-part-one-introduction","status":"publish","type":"post","link":"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/","title":{"rendered":"Mahout &#8211; Taste :: Part 1 &#8211; Introduction"},"content":{"rendered":"<p>This post is the first in a series on Taste, a Java framework for providing personalized recommendations. Taste is part of the larger <a href=\"http:\/\/lucene.apache.org\/mahout\/taste.html\">Mahout<\/a> framework, which features various scalable machine-learning algorithms. In this post I introduce you to the concepts of personalized recommendations, also known as <a href=\"http:\/\/en.wikipedia.org\/wiki\/Collaborative_filtering\">collaborative filtering<\/a>. After this introduction, Taste&#8217;s architecture and extension points are explained. I finish this post by demonstrating and explaining the <code>TanimotoCoefficientSimilarity<\/code>, one of Taste&#8217;s implementations used for computing recommendations.<br \/>\n<!--more--><\/p>\n<p><strong>Personalized Recommendations<\/strong><\/p>\n<p>Today the web is full of services for recommending books, websites, music, applications, movies and so on. <a href=\"http:\/\/www.amazon.com\">Amazon<\/a>, <a href=\"http:\/\/www.last.fm\">Last.fm<\/a> and <a href=\"http:\/\/www.stumbleupon.com\">StumbleUpon<\/a>, all provide these personalized recommendations for internet users. These features can be quite useful for customers and profitable for many e-commerce sites these days.<\/p>\n<p><strong>Collaborative Filtering<\/strong><\/p>\n<p>Let&#8217;s first review some basic concepts. The theory that powers all these useful websites mentioned above is the process of <a href=\"http:\/\/en.wikipedia.org\/wiki\/Collaborative_filtering\">Collaborative Filtering<\/a>, or pattern recognition in large datasets of multiple users. These datasets can contain preferences of users for certain items. For example, Youtube members can rate a video by assigning a number of stars. The number of stars is a user&#8217;s preference value, a value from 1 to 5. Based on this collection of personal preferences and a &#8216;similarity function&#8217; you can recommend videos to users or determine similar users, users with similar taste in videos. In this case, recommending videos is an example of an &#8216;item-based recommendation&#8217; and determining users with similar tastes is an example of an &#8216;user-based recommendation&#8217;.<\/p>\n<p><strong>Introducing Mahout &#8211; Taste<\/strong><\/p>\n<p>So how can we use this theory to build recommenders? This is where Mahout &#8211; Taste comes in. <a href=\"http:\/\/lucene.apache.org\/mahout\/\">Mahout<\/a> is a Java framework for running scalable machine learning algorithms on top of Hadoop. <a href=\"http:\/\/lucene.apache.org\/mahout\/taste\">Taste<\/a> is a sub-framework of Mahout for building recommendation engines. Since April 4th 2008, Taste has become part of Mahout. Below is a figure with Taste&#8217;s architecture and the building blocks you need to configure a recommender.<\/p>\n<p><figure id=\"attachment_1479\" aria-describedby=\"caption-attachment-1479\" style=\"width: 354px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-1479\" title=\"taste-architecture\" src=\"http:\/\/blog.jteam.nl\/wp-content\/uploads\/2009\/12\/taste-architecture.png\" alt=\"taste-architecture\" width=\"354\" height=\"448\" srcset=\"https:\/\/trifork.nl\/blog\/wp-content\/uploads\/sites\/3\/2009\/12\/taste-architecture.png 553w, https:\/\/trifork.nl\/blog\/wp-content\/uploads\/sites\/3\/2009\/12\/taste-architecture-237x300.png 237w\" sizes=\"auto, (max-width: 354px) 100vw, 354px\" \/><figcaption id=\"caption-attachment-1479\" class=\"wp-caption-text\">Taste architecture diagram<\/figcaption><\/figure><\/p>\n<p style=\"text-align: center\">\n<p>The main building block in Taste is the <code>Recommender<\/code>. The <code>Recommender<\/code> recommends items based on a given item or it determines users with similar tastes. It works as follows: the recommender applies a similarity function on a subset of pairs of items (or users) in the dataset. A similarity function usually returns a value between 0 and 1, with 1 representing two completely similar items and 0 completely dissimilar items. When the similarity function processes pairs in the dataset the resulting similarity values are collected and are either kept in memory or stored on the filesystem or a database. When the Java application requests\u00a0a few recommendations for a given item, the <code>Recommender<\/code> returns the items with the highest similarity.<\/p>\n<p>The Recommender retrieves items and users through the <code>DataModel<\/code> abstraction. Taste contains <code>DataModel<\/code> implementations for retrieving and storing your dataset through the filesystem or a database. In addition, the <code>DataModel<\/code> provides methods that count the total number of users, total number of items, number of users that prefer a certain item, and many more functions. Similarity functions use these numbers to compute a similarity value for pairs of items or users. This will be shown later in the example of the <code>TanimotoCoefficientSimilarity<\/code>, which determines a ratio based on some of these figures. You can build a recommender with Taste by adding a <code>DataModel<\/code> and a similarity function to a <code>Recommender<\/code>. You can also define your own similarity function by extending <code>UserSimilarity<\/code> or <code>ItemSimilarity<\/code> to recommend users or items, respectively.<\/p>\n<p><strong>Tanimoto coefficent similarity<\/strong><\/p>\n<p>Taste contains around a dozen similarity algorithms you can choose from to build a recommender. For this introductory post I will explain Taste&#8217;s <code>TanimotoCoefficientSimilarity<\/code>, a relatively straightforward similarity algorithm that is widely used in <a href=\"http:\/\/books.google.nl\/books?id=7VofXg_d5Y8C&amp;pg=PA105&amp;lpg=PA105&amp;dq=tanimoto+coefficient++introduction&amp;source=bl&amp;ots=l9ExLXcgz5&amp;sig=IB9VD9G87lSKqcADb0GcTz1QTms&amp;hl=nl&amp;ei=4tMWS6_2D9Wd4Qb1wcDcBg&amp;sa=X&amp;oi=book_result&amp;ct=result&amp;resnum=3&amp;ved=0CBYQ6AEwAg#v=onepage&amp;q=&amp;f=false\">chemo-informatics<\/a> for discovering similarities between molecules. Let&#8217;s illustrate the algorithm in the context of a webshop. Suppose there are 3 customers, A, B and C and 5 products, numbered 1 up to 5. Say each customer has bought a few products. For this algorithm it does not matter how many products are purchased, only which products are purchased by which customer. See the table below.<\/p>\n<p><figure id=\"attachment_1429\" aria-describedby=\"caption-attachment-1429\" style=\"width: 321px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-1429\" title=\"tanimoto\" src=\"http:\/\/blog.jteam.nl\/wp-content\/uploads\/2009\/11\/tanimoto1.png\" alt=\"Customer purchases\" width=\"321\" height=\"102\" srcset=\"https:\/\/trifork.nl\/blog\/wp-content\/uploads\/sites\/3\/2009\/11\/tanimoto1.png 321w, https:\/\/trifork.nl\/blog\/wp-content\/uploads\/sites\/3\/2009\/11\/tanimoto1-300x95.png 300w\" sizes=\"auto, (max-width: 321px) 100vw, 321px\" \/><figcaption id=\"caption-attachment-1429\" class=\"wp-caption-text\">Customer purchases<\/figcaption><\/figure><\/p>\n<p>Intuitively you may see that the similarity between two products can be expressed by some ratio of purchases of customers. To be more precise, the tanimoto coefficient is computed by the following formula:<\/p>\n<p>$$!\\frac{c}{a + b &#8211; c}$$<\/p>\n<p>$$c = $$ Number of customers that purchased p1 and p2<br \/>\n$$a = $$ Number of customers that purchased p1<br \/>\n$$b = $$ Number of customers that purchased p2<\/p>\n<p>This means that if many customers have bought products, the numerator will be higher and so will be the similarity value. Alternatively, if many people have bought p1 and many have bought p2, but very few people bought both, p1 and p2 are probably dissimilar. Below is a table with calculated tanimoto coefficients for each product pair:<\/p>\n<p><figure id=\"attachment_1558\" aria-describedby=\"caption-attachment-1558\" style=\"width: 492px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-1558\" title=\"tanimoto_calculations\" src=\"http:\/\/blog.jteam.nl\/wp-content\/uploads\/2009\/12\/tanimoto_calculations.png\" alt=\"tanimoto_calculations\" width=\"492\" height=\"102\" srcset=\"https:\/\/trifork.nl\/blog\/wp-content\/uploads\/sites\/3\/2009\/12\/tanimoto_calculations.png 492w, https:\/\/trifork.nl\/blog\/wp-content\/uploads\/sites\/3\/2009\/12\/tanimoto_calculations-300x62.png 300w\" sizes=\"auto, (max-width: 492px) 100vw, 492px\" \/><figcaption id=\"caption-attachment-1558\" class=\"wp-caption-text\">Tanimoto coefficients for all product pairs<\/figcaption><\/figure><\/p>\n<p><strong>Demonstrating Taste<\/strong><\/p>\n<p>In this section I demonstrate how to express the previous example with Taste.\u00a0 If you like to try this example at home, download the <a href=\"http:\/\/lucene.apache.org\/mahout\/#17+Nov.+2009+-+Apache+Mahout+0.2+released\">brand new<\/a> 0.2 mahout jar <a href=\"http:\/\/lucene.apache.org\/mahout\/releases.html\">here<\/a> and add it to your classpath. If you are using maven, add the following snippet to your pom.xml<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;dependency&gt;\n    &lt;groupId&gt;org.apache.mahout&lt;\/groupId&gt;\n    &lt;artifactId&gt;mahout-core&lt;\/artifactId&gt;\n    &lt;version&gt;0.2&lt;\/version&gt;\n&lt;\/dependency&gt;\n<\/pre>\n<p>Below is a code snippet that shows how to build the <code>DataModel<\/code> and how to compute similarities with the <code>TanimotoCoefficientSimilarity<\/code>.\u00a0 In the <code>setup()<\/code> method I create a <code>BooleanPreferenceArray<\/code> for each user. I then fill these arrays, put all of them in a <code>FastByIdMap<\/code> and put that in the <code>DataModel<\/code>. Next I create the <code>TanimotoCoefficientSimilarity<\/code> and pass in the <code>DataModel<\/code>. I then write a few tests that check whether the similarities computed by Taste return the values I expect, given the formula above.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\n\/**\n * Demonstrates TanimotoCoefficientSimilarity + recommender.\n *\n * @author Frank Scholten\n *\/\npublic class TanimotoDemo {\n\n private DataModel dataModel;\n private ItemSimilarity tanimoto;\n\n private long CUSTOMER_A = 0;\n private long CUSTOMER_B = 1;\n private long CUSTOMER_C = 2;\n\n private long productOne = 0;\n private long productTwo = 1;\n private long productThree = 2;\n private long productFour = 3;\n private long productFive = 4;\n\n @Before\n public void setup() {\n   FastByIDMap&lt;PreferenceArray&gt; userIdMap = new FastByIDMap&lt;PreferenceArray&gt;();\n\n   BooleanUserPreferenceArray customerAPrefs = new BooleanUserPreferenceArray(4);\n   customerAPrefs.set(0, new BooleanPreference(CUSTOMER_A, productOne));\n   customerAPrefs.set(1, new BooleanPreference(CUSTOMER_A, productTwo));\n   customerAPrefs.set(2, new BooleanPreference(CUSTOMER_A, productFour));\n   customerAPrefs.set(3, new BooleanPreference(CUSTOMER_A, productFive));\n\n   BooleanUserPreferenceArray customerBPrefs = new BooleanUserPreferenceArray(3);\n   customerBPrefs.set(0, new BooleanPreference(CUSTOMER_B, productTwo));\n   customerBPrefs.set(1, new BooleanPreference(CUSTOMER_B, productThree));\n   customerBPrefs.set(2, new BooleanPreference(CUSTOMER_B, productFive));\n\n   BooleanUserPreferenceArray customerCPrefs = new BooleanUserPreferenceArray(2);\n   customerCPrefs.set(0, new BooleanPreference(CUSTOMER_C, productOne));\n   customerCPrefs.set(1, new BooleanPreference(CUSTOMER_C, productFive));\n\n   userIdMap.put(CUSTOMER_A, customerAPrefs);\n   userIdMap.put(CUSTOMER_B, customerBPrefs);\n   userIdMap.put(CUSTOMER_C, customerCPrefs);\n\n   dataModel = new GenericDataModel(userIdMap);\n   tanimoto = new TanimotoCoefficientSimilarity(dataModel);\n }\n\n @Test\n public void testSimilarities() throws TasteException {\n   assertEquals((double) 1, tanimoto.itemSimilarity(productOne, productOne), 0.01);\n   assertEquals((double) 1 \/ 3, tanimoto.itemSimilarity(productOne, productTwo), 0.01);\n   assertEquals((double) 0, tanimoto.itemSimilarity(productOne, productThree), 0.01);\n   assertEquals((double) 1 \/ 2, tanimoto.itemSimilarity(productOne, productFour), 0.01);\n   assertEquals((double) 2 \/ 3, tanimoto.itemSimilarity(productOne, productFive), 0.01);\n\n   assertEquals((double) 1 \/ 1, tanimoto.itemSimilarity(productTwo, productTwo), 0.01);\n   assertEquals((double) 1 \/ 2, tanimoto.itemSimilarity(productTwo, productThree), 0.01);\n   assertEquals((double) 1 \/ 2, tanimoto.itemSimilarity(productTwo, productFour), 0.01);\n   assertEquals((double) 2 \/ 3, tanimoto.itemSimilarity(productTwo, productFive), 0.01);\n\n   assertEquals((double) 1, tanimoto.itemSimilarity(productThree, productThree), 0.01);\n   assertEquals((double) 0, tanimoto.itemSimilarity(productThree, productFour), 0.01);\n   assertEquals((double) 1 \/ 3, tanimoto.itemSimilarity(productThree, productFive), 0.01);\n\n   assertEquals((double) 1, tanimoto.itemSimilarity(productFour, productFour), 0.01);\n   assertEquals((double) 1 \/ 3, tanimoto.itemSimilarity(productFour, productFive), 0.01);\n\n   assertEquals((double) 1, tanimoto.itemSimilarity(productFive, productFive), 0.01);\n }\n\n @Test\n public void testRecommendProducts() throws TasteException {\n   ItemBasedRecommender recommender = new GenericItemBasedRecommender(dataModel, tanimoto);\n\n   List&lt;RecommendedItem&gt; similarToProductThree = recommender.mostSimilarItems(productThree, 2);\n\n   assertEquals(productTwo, similarToProductThree.get(0).getItemID());\n   assertEquals(productFive, similarToProductThree.get(1).getItemID());\n }\n}\n<\/pre>\n<p>I also added tests for the recommendations themselves. The <code>testRecommendProducts()<\/code> method uses <code>mostSimilarItems<\/code> to determine items similar to product 3, in terms of customer preferences. The second parameter of this method is the number of similar items to compute. The result of this method is a list of items ordered by their similarity value, descendingly. We can now predict and see that product two is most similar to product three and product five is second most similar. Note that the code above is only suitable for demonstrative purposes to demonstrate and understand the algorithm. For instance, in an actual a production ready implementation a database backed <code>DataModel<\/code> can be used, or the algorithm can be ran on Hadoop.<\/p>\n<p>This concludes this introduction to Taste. There are a lot of interesting parts that I haven&#8217;t explored myself, I am learning this one piece at a time, including the algorithms and mathematics behind it.  Some things to check out: the <a href=\"http:\/\/lucene.apache.org\/mahout\/javadoc\/core\/org\/apache\/mahout\/cf\/taste\/impl\/similarity\/package-summary.html\">similarity Javadocs<\/a> for similarity algorithms. And of course there are classes to run your recommender on <a href=\"http:\/\/blog.jteam.nl\/2009\/08\/04\/introduction-to-hadoop\/\">Hadoop<\/a> and to evaluate the quality of your recommender with training sets. In the next few posts I will go into some of these subjects and use examples with a larger dataset, look into Hadoop and do a comparison of algorithms.<\/p>\n<p><strong>References<\/strong><\/p>\n<ul>\n<li><a href=\"http:\/\/lucene.apache.org\/mahout\/taste.html\">http:\/\/lucene.apache.org\/mahout\/taste.html<\/a> &#8211; Taste homepage<\/li>\n<li><a href=\"http:\/\/lucene.apache.org\/mahout\/mailinglists.html\">http:\/\/lucene.apache.org\/mahout\/mailinglists.html<\/a> &#8211; Mahout mailing list<\/li>\n<li><a href=\"http:\/\/www.ibm.com\/developerworks\/java\/library\/j-mahout\/\">http:\/\/www.ibm.com\/developerworks\/java\/library\/j-mahout\/<\/a> &#8211; Mahout Article by Grant Ingersoll<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This post is the first in a series on Taste, a Java framework for providing personalized recommendations. Taste is part of the larger Mahout framework, which features various scalable machine-learning algorithms. In this post I introduce you to the concepts of personalized recommendations, also known as collaborative filtering. After this introduction, Taste&#8217;s architecture and extension [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":""},"categories":[40,15,10],"tags":[42,35,156,157,11,158,159],"class_list":["post-324","post","type-post","status-publish","format-standard","hentry","category-mahout","category-enterprise-search","category-development","tag-apache","tag-lucene","tag-mahout","tag-collaborative_filtering","tag-java","tag-recommendations","tag-taste"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Mahout - Taste :: Part 1 - Introduction - Trifork Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Mahout - Taste :: Part 1 - Introduction - Trifork Blog\" \/>\n<meta property=\"og:description\" content=\"This post is the first in a series on Taste, a Java framework for providing personalized recommendations. Taste is part of the larger Mahout framework, which features various scalable machine-learning algorithms. In this post I introduce you to the concepts of personalized recommendations, also known as collaborative filtering. After this introduction, Taste&#8217;s architecture and extension [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/\" \/>\n<meta property=\"og:site_name\" content=\"Trifork Blog\" \/>\n<meta property=\"article:published_time\" content=\"2009-12-09T10:06:36+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/blog.jteam.nl\/wp-content\/uploads\/2009\/12\/taste-architecture.png\" \/>\n<meta name=\"author\" content=\"frank\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"frank\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/\",\"url\":\"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/\",\"name\":\"Mahout - Taste :: Part 1 - Introduction - Trifork Blog\",\"isPartOf\":{\"@id\":\"https:\/\/trifork.nl\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/#primaryimage\"},\"thumbnailUrl\":\"http:\/\/blog.jteam.nl\/wp-content\/uploads\/2009\/12\/taste-architecture.png\",\"datePublished\":\"2009-12-09T10:06:36+00:00\",\"author\":{\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/00fad6c5829f6770345f23ccace2e54f\"},\"breadcrumb\":{\"@id\":\"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/#primaryimage\",\"url\":\"http:\/\/blog.jteam.nl\/wp-content\/uploads\/2009\/12\/taste-architecture.png\",\"contentUrl\":\"http:\/\/blog.jteam.nl\/wp-content\/uploads\/2009\/12\/taste-architecture.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/trifork.nl\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Mahout &#8211; Taste :: Part 1 &#8211; Introduction\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/trifork.nl\/blog\/#website\",\"url\":\"https:\/\/trifork.nl\/blog\/\",\"name\":\"Trifork Blog\",\"description\":\"Keep updated on the technical solutions Trifork is working on!\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/trifork.nl\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/00fad6c5829f6770345f23ccace2e54f\",\"name\":\"frank\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/5c39a948f2b70fa900b25dc79cde8643?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/5c39a948f2b70fa900b25dc79cde8643?s=96&d=mm&r=g\",\"caption\":\"frank\"},\"url\":\"https:\/\/trifork.nl\/blog\/author\/frank\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Mahout - Taste :: Part 1 - Introduction - Trifork Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/","og_locale":"en_US","og_type":"article","og_title":"Mahout - Taste :: Part 1 - Introduction - Trifork Blog","og_description":"This post is the first in a series on Taste, a Java framework for providing personalized recommendations. Taste is part of the larger Mahout framework, which features various scalable machine-learning algorithms. In this post I introduce you to the concepts of personalized recommendations, also known as collaborative filtering. After this introduction, Taste&#8217;s architecture and extension [&hellip;]","og_url":"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/","og_site_name":"Trifork Blog","article_published_time":"2009-12-09T10:06:36+00:00","og_image":[{"url":"http:\/\/blog.jteam.nl\/wp-content\/uploads\/2009\/12\/taste-architecture.png","type":"","width":"","height":""}],"author":"frank","twitter_card":"summary_large_image","twitter_misc":{"Written by":"frank","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/","url":"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/","name":"Mahout - Taste :: Part 1 - Introduction - Trifork Blog","isPartOf":{"@id":"https:\/\/trifork.nl\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/#primaryimage"},"image":{"@id":"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/#primaryimage"},"thumbnailUrl":"http:\/\/blog.jteam.nl\/wp-content\/uploads\/2009\/12\/taste-architecture.png","datePublished":"2009-12-09T10:06:36+00:00","author":{"@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/00fad6c5829f6770345f23ccace2e54f"},"breadcrumb":{"@id":"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/#primaryimage","url":"http:\/\/blog.jteam.nl\/wp-content\/uploads\/2009\/12\/taste-architecture.png","contentUrl":"http:\/\/blog.jteam.nl\/wp-content\/uploads\/2009\/12\/taste-architecture.png"},{"@type":"BreadcrumbList","@id":"https:\/\/trifork.nl\/blog\/mahout-taste-part-one-introduction\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/trifork.nl\/blog\/"},{"@type":"ListItem","position":2,"name":"Mahout &#8211; Taste :: Part 1 &#8211; Introduction"}]},{"@type":"WebSite","@id":"https:\/\/trifork.nl\/blog\/#website","url":"https:\/\/trifork.nl\/blog\/","name":"Trifork Blog","description":"Keep updated on the technical solutions Trifork is working on!","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/trifork.nl\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/00fad6c5829f6770345f23ccace2e54f","name":"frank","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/5c39a948f2b70fa900b25dc79cde8643?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5c39a948f2b70fa900b25dc79cde8643?s=96&d=mm&r=g","caption":"frank"},"url":"https:\/\/trifork.nl\/blog\/author\/frank\/"}]}},"_links":{"self":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts\/324","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/comments?post=324"}],"version-history":[{"count":0,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts\/324\/revisions"}],"wp:attachment":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/media?parent=324"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/categories?post=324"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/tags?post=324"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}