[As community content, this post reflects the views and opinions of the particular author and does not necessarily reflect the official stance of Neo4j. This post was originally published on Kevin Van Gundy’s blog.]
Compensation planning and calculations in complex sales organizations can be incredibly taxing on traditional databases. Sufficiently large organizations often will end up batching these processes overnight or into a weekly job. For the purposes of this blog post, let’s take a look at Slashco: the hottest multi-level marketing “guild” in the World of Warcraft. Get the full datasets and Cypher queries used in this blog post here. In this guild, “associates” may join up and sell Slashco’s fine adventuring gear to the many peoples of Azeroth as well as recruit their friends and family to also sell Slashco products. When an associate recruits someone to join the guild, that new member becomes a part of the associate’s “down-stream.” As a royalty for bringing on this new member, associates will receive a small commission of every item sold by members “down-stream” of them. In this compensation schedule we have sales-mages who will both sell products directly as well as recruit people to also sell products on behalf of Slashco. I created a sample model based on popular multi-level marketing model. It comprises of four income streams:- Direct Sales: For each item a team-member sells directly, they earn a commission.
- Downstream Royalty: A percentage earned of the retail price of items sold by people “within their downstream,” meaning those that they have recruited to work for Slashco and by extension those who their recruits have recruited.
- Wholesale Profit: A percentage earned on the goods sold to those “within their downstream” (these goods will then be re-sold to consumers.
- Global Sales Royalty: A percentage of all sales made by those within Slashco (a.k.a. revenue sharing).
- Commission due to each rep, by period, in accord with compensation rules
- Commission due to each rep, annually in accord with compensation rules
- Sales Leaderboard
- Top Sales Rep by Total Sales
- Top Sales Rep by Largest Deal
- Global reporting
- Sales by period
- Top selling items
- Recommendations
- What items are most frequently sold together?
Slaschco Sales Compensation Application Data Model:
The scripts I’m using to build this example are located in this git repo. Now that we have a data model, let’s fire up Neo4j and pass in our import script (found here). Essentially what we’re doing is creating a few constraints and indexes, then telling Neo4j how to interpret our CSV files into the above model. Now that we’ve loaded in all of our data, let’s open up our browser and start answering some of our top queries.We’ll Work Backwards:
5. Recommendation
- What items are most frequently sold together?
//recommendation engine, what items are most frequently co-sold? MATCH path = (item:Item)-[:CONTAINS]-(:Transaction)-[:CONTAINS]-(item2:Item) WHERE id(item) > id(item2) WITH item, item2, count(distinct path) as instances ORDER BY instances DESC LIMIT 3 RETURN item.name, item2.name, instances;
4. Global reporting
- Sales by period
- Top selling items
//total sales volume by period descending MATCH (p:Period)-[:OCCURED_IN]-(t:Transaction)-[:CONTAINS]-(i:Item) WITH sum(i.price) as sales, p ORDER BY sales DESC LIMIT 10 RETURN sales, p.period;
MATCH (t:Transaction)-[:CONTAINS]-(i:Item) WITH count(distinct(t)) as itemSales, i ORDER BY itemSales DESC LIMIT 5 RETURN i.name as name, itemSales as count;
3. Sales Leaderboard
- Top Sales Rep by Total Sales Volume
- Top Sales Rep by Largest Deal
//Who has sold the most volume? MATCH (rep)-[:SOLD]-(txn)-[:CONTAINS]-(itm) WITH rep, round(sum(itm.price)) as volume ORDER BY volume DESC LIMIT 5 RETURN rep.name as name, volume;
//Who closed the largest deal? MATCH (rep)-[:SOLD]-(txn) WITH rep, txn MATCH (txn)-[:CONTAINS]-(itm) WITH rep, txn, round(sum(itm.price)) as dealSize ORDER BY dealSize DESC LIMIT 5 RETURN rep.name as name, txn.transactionID as transction, dealSize as `deal size`;
2. Commission due to each rep, annually in accord with compensation rules
Due to the complexity of the queries, I decided to run them with each level of rep separated out into its own query, however they all follow the basic form of the “what do I do with all this gold” query://level 6 comp MATCH (transaction)-[:CONTAINS]-(item) WITH sum(item.price*.05) as globalRoyalty MATCH (big_boss:Person {level:6})<-[r:REPORTS_TO*..]-(downStreamers)-[:SOLD]-(transaction)-[:CONTAINS]-(item) WITH sum(item.price*.1)+sum(item.wholesalePrice*.5) + globalRoyalty as downStreamGlobal6, big_boss MATCH (boss)-[:SOLD]-(transaction)-[:CONTAINS]-(item) WITH sum(item.price*.65) + downStreamGlobal6 as tc6, big_boss.name as n6 RETURN tc6, n6;
1. Commission due to each rep, by period in accord with compensation rules
This looks frighteningly similar to our last query, except we’ve added a short pattern(transaction)-[:OCCURRED_IN]-(period {period:35})
which will filter out all transactions that occurred in periods that are not the 35th. We still see that over a reasonable sized dataset (100 employees, 20k items, 10k transactions), neo4j is lightning fast.
//level 6 comp with time period MATCH (transaction)-[:OCCURRED_IN]-(p:Period {period:35}) WITH transaction, p MATCH (transaction)-[:CONTAINS]-(item) WITH sum(item.price*.05) as globalRoyalty, p MATCH (transaction)-[:OCCURRED_IN]-(p:Period {period:35}) WITH globalRoyalty, p, transaction MATCH (big_boss:Person {level:6})<-[r:REPORTS_TO*..]-(downStreamers)-[:SOLD]-(transaction)-[:CONTAINS]-(item) WITH sum(item.price*.1)+sum(item.wholesalePrice*.5) + globalRoyalty as downStreamGlobal6, big_boss, p MATCH (transaction)-[:OCCURRED_IN]-(p:Period {period:35}) WITH transaction, downStreamGlobal6, big_boss MATCH (boss)-[:SOLD]-(transaction)-[:CONTAINS]-(item) WITH sum(item.price*.65) + downStreamGlobal6 as tc6, big_boss.name as n6 RETURN tc6, n6;//kvg Want to learn more about graph databases? Click below to get your free copy of O’Reilly’s Graph Databases ebook and discover how to use graph solutions for your mission-critical problems today.