Use these instructions to build a Product Recommender application that uses Saffron Technology™ APIs and thought processes (THOPs).
Note: The Product Recommender is also referred to as SaffronOne.
Overview
The Saffron Technology Natural Intelligence Platform offers a personalization solution that enables multi-channel and multi-product businesses to anticipate individual consumer behavior and thus market to that consumer the right products or services at the right time and in the right channel.
Note: The term consumer can refer to a customer or member or group.
Use Case
Predict or recommend a product for a consumer based on both current and previous purchases of other consumers with similar consumer characteristics.
Workflow
Individual data, including demographics and past product purchases, is collected and stored for all consumers. A consumer can represent one person or a group of people such as a group of members on an insurance plan. Product purchase information for all consumers is also collected and stored. In order to recommend a product for an inquiring consumer, the current situation of that consumer is retrieved. The situation for a consumer is the current snapshot of all characteristics that defines that consumer such as purchased products and demographics. The consumer's situation is then compared with other consumers who have similar situations. Purchases made by these similar consumers are recommended to the inquiring consumer, and in ranked order.
How it Works
1. Create two Spaces for consumer and product data
Create a consumer_space Space and a product_space Space. These Spaces are used for the following purposes:
- ETL configuration
- The Spaces store the ETL configuration for your specified data and stores the settings for your data ingestion.
Location of consumer and product data sources- consumer_space
- This Space holds records of individual consumer data called situations. Data that makes up a situation can include such items as personal and financial information, and purchase history. This information is used to look for consumers who have similar situations and view their purchase histories. Note that a consumer can represent one person or a group of people such as a group of members on an insurance plan.
- product_space
- This Space includes product purchase information such as the name of a product, purchase dates, and other associated information. This information is used to create product.
- memories
- Used to make recommendations for consumers.
The locations of your data Sources (consumer and prduct) are stored in the respective Space along with definitions for parsing and mapping the data. Once all configurations are complete, both Spaces are published and the data can be ingested. The knowledge discovered in your data is stored in the SaffronMemoryBase™. This information is used to make product recommendations for consumers, as described in the following steps.
2. Find consumers
Saffron makes a connections call to return a list of consumers from the consumer_spaceSpace. These are customers for whom you wish to make product recommendations:
Input: //url/consumer_space/connections/c=consumer Output: { c:consumer v: 12380 c:consumer v: 76498 }
3. Get the current "situation" for the consumer
Saffron makes a connections call to query each consumer or a specific consumer (q=consumer:ID) from the consumer_space Space. It outputs the current attributes for this consumer (or consumers in the Space) at this particular moment in time. In the example below, consumer 12380 is queried:
Input: For each consumer //url/consumer_space/connections/q=consumer:12380 Output: { c:consumer v: 12380 c:name v: John_Smith c:age v: 30 c:Destination v: Italy c:Airline v: Delta }
4. Build an AQL
Saffron builds an AQL from the current attributes information for that consumer:
q=("consumer":"12380", "name":"John_Smith", "age":"30", "Destination":"Italy", "Airline":"Delta")
5. Get a list of recommended products for the consumer
Saffron performs a new connections call from the product_space Space to find products that consumers with similar attributes have purchased. This call returns a list of the closest recommended products as well as the metric score, which shows the strength of the product recommendation.
Note that a metric score of 1.0 does not mean that the recommended product (Gold, in our example below) is an exact match. It means that this product recommendation is the closest match to the consumer's situation.
Input: For each consumer //url/product_space/connections/q=aql & c=product Output: { c:product v: Gold m: 1 c:product v: Platinum m: 0.99 c:product v: Silver m: 0.94 }
6. (Optional) Filter current products or other categories
Saffron can make a connections call from the product_spaceSpace to filter out products that a consumer already has to avoid including it as a recommendation. Categories that might not apply to a specific group of consumers can also be filtered out:
Input: //url/product_space/connections/f=current_products Output: { c:product v: Silver m: 0.94 }
7. View the CSV report that lists recommended products for the consumer
Consumer, Product, Rank, Evidence 12380, Gold, 1, age: 30 (0.8), Destination: Italy (0.2) 12380, Platinum, 0.99, age: 30 (0.4), Destination: Italy (0.4), Airline: Delta (0.2)
Thought Processes
Use (or customize) the Product Recommender THOP to perform the steps outlined above.
function run(p,log) { // Member Space var memberSpace = 'trip_insurance_consumer' // Product Space var productSpace = 'trip_insurance_product' // Member Category var memberCategory = 'enrlid' // Product Category var productCategory = 'productname'; // Other variables var page = 1; var currentstatepageSize = 25; var numberOfMembers = 2; var results = []; // Get list of members from Member Space var members = getMembers(memberSpace, memberCategory, numberOfMembers); // For each member in the Member Space, get their current situation vector and // Recommend products with evidence for(var i=0; i < members.length; i++) { // Get current state vector var currentStateAttrs = getCurrentState(memberSpace, memberCategory, members[i], page, currentstatepageSize) // Build AQL var aql = buildCurrentMemberStateQuery(currentStateAttrs); // Get list of recommended products var recommendedProducts = getProductRecommendations(productSpace, aql, memberCategory, productCategory); // For each product recommended, output evidence for the recommendation for(var k=0; k < recommendedProducts.length; k++) { var result = ({'Member':members[i],'Product':recommendedProducts[k].product,'RScore':recommendedProducts[k].rollup_score,'Score':recommendedProducts[k].score,'Evidence':recommendedProducts[k].evidence}) results.push(result); } } // Return results in JSON format return JSON.stringify(results); } // Function to get list of members function getMembers(space, memberCategory, numberOfMembers) { var members = []; var membersUrl = new Smb('localhost:8080','demo','12345').connections(space).c(memberCategory).p(1).ps(numberOfMembers) membersUrl.get().r.forEach(function (r) { members.push(r.a.v); }); return members; } // Function to get current state vector function getCurrentState(space, memberCategory, member, page, pageSize) { var currentStateAttrs = [{category: memberCategory, value: member}]; var currentStateUrl = new Smb('localhost:8080','demo','12345') .connections(space).q(cat(memberCategory, member)) .p(page).ps(pageSize) currentStateUrl.get().r.forEach(function (r) { currentStateAttrs.push({category: r.a.c, value: r.a.v}); }); return currentStateAttrs; } // function to build AQL function buildCurrentMemberStateQuery(currentStateAttrs) { var aql = '('; for(var i=0; i < currentStateAttrs.length; i++) { aql += cat(currentStateAttrs[i].category, currentStateAttrs[i].value) + '' } aql += ')'; return aql; } // function to get list of recommended products function getProductRecommendations(space, q, memberCategory, productCategory) { // Filter these categories from the evidence var filter_categories = ['age', 'count_of_sessions','days_since_last_session', 'fname', 'lname','miscproviders', 'session_duration', 'source','totalcost', 'totaldays']; var recommendedProducts = []; // This below line is if we want to use Cognitive Distance and auto-target // "separate" (me=as), meaning that association counts are voted between // multiple memories //var recommendedProductsUrl = new Smb('localhost:8080','demo','12345') //.connections(space).q(q).category(productCategory).me('as').ml(2).sm(2) // For this use case we use Frequency and Directory Memory var recommendedProductsUrl = new Smb('localhost:8080','demo','12345') .connections(space).q(q) .category(productCategory).ml(2).ps("5") recommendedProductsUrl.get().r.forEach(function (r) { var expAttrs = []; r.exp.forEach(function (exp) { if(filter_categories.indexOf(exp.a.c) == -1){ expAttrs.push(exp.a.c + ":" + exp.a.v + " S:" + exp.am[0].s); } }); recommendedProducts.push({product: r.a.v, rollup_score: r.m, score: r.am[0].s, evidence: expAttrs.join(" | ")}); }); return recommendedProducts; } // Other Essential Functions // function to prepare results function prepareResult(r) { var o = {}; o[r.a.c] = r.a.v; o.score = r.m; return o; } // Concatenate function function cat(c,v) { return v ? '"' + c + '":"' + v + '"' : ''; }