Mark received an email from some company which read:
"Hi Mark, I recently found your profile in our database, and your background is impressive. The (redacted big company) Media Division will be flying several candidates in for interviews at our (redacted big city) headquarters in April and considering you."
See it here: drdobbs.com/tools/my-big-company-code-interview
I decided to tackle the challenge as well. However, I decided to use a NOSQL database to store the users and products and users. I also introduced a 'Store' to which the products and users belong.
I decided to use Neo4J graph database as it naturally lends itself to the problem domain, The Store is defined as follows:
@NodeEntity
public class Store {
@GraphId
private Long id;
@Indexed(indexType = IndexType.FULLTEXT, indexName = "storeName")
private String storeName;
@RelatedTo(type = RelationshipTypes.PRODUCT_BELONGS_TO, direction = Direction.BOTH)
private Set products;
@RelatedTo(type = RelationshipTypes.BELONGS_TO, direction = Direction.BOTH)
private Set users;
...
...
The User is defined as follows:
@NodeEntity
public class User extends BaseEntity implements Comparable {
@GraphId
private Long id;
@Indexed(indexType = IndexType.FULLTEXT, indexName = "firstName")
private String firstName;
@Indexed(indexType = IndexType.FULLTEXT, indexName = "lastName")
private String lastName;
private String currency;
@RelatedTo(type = RelationshipTypes.IS_FRIEND_OF, direction = Direction.BOTH)
private Set friends;
@RelatedTo(type = RelationshipTypes.BOUGHT_PRODUCT, direction = Direction.BOTH)
private Set products;
@RelatedTo(type = RelationshipTypes.BELONGS_TO, direction = Direction.BOTH)
private Store store;
...
...
The Product is defined as follows:
@NodeEntity
public class Product extends BaseEntity implements Comparable {
@GraphId
private Long id;
@Indexed(indexType = IndexType.FULLTEXT, indexName = "sku")
private String sku;
private BigDecimal price;
private String currency;
@RelatedTo(type = RelationshipTypes.BOUGHT_PRODUCT, direction = Direction.BOTH)
private Set users;
@RelatedTo(type = RelationshipTypes.PRODUCT_BELONGS_TO, direction = Direction.BOTH)
private Store store;
...
...
and the relationships are defined as follows:
public class RelationshipTypes {
public static final String IS_FRIEND_OF = "IS_FRIEND_OF";
public static final String BOUGHT_PRODUCT = "BOUGHT_PRODUCT";
public static final String BELONGS_TO = "BELONGS_TO";
public static final String PRODUCT_BELONGS_TO = "PRODUCT_BELONGS_TO";
}
Here is the repository class foe the User:
public interface UserRepository {
@Query("START user=node:User(lastName={0}) RETURN user")
User findUserByName(String name);
@Query("START user=node({0}) MATCH products-[:BOUGHT_PRODUCT] RETURN nodes(products)")
Iterable> getUserProducts(User user);
@Query("START user=node({0}) MATCH friends-[:IS_FRIEND_OF] RETURN nodes(friends)")
Iterable> getUserFriends(User user);
}
and here is the repository class for the product:
public interface ProductRepository {
@Query("START product=node:Product(sku={0}) RETURN product")
Product findProductByName(String name);
}
Sample products:
<products><br /> <product currency="USD" name="Surf" price="1.30"><br /> <product currency="USD" name="Cheese" price="1.10"><br /> <product currency="USD" name="White Bread" price="1.90"><br /> <product currency="USD" name="Brown Bread" price="1.07"><br /> <product currency="USD" name="Dozen Eggs" price="1.14"><br /></product></product></product></product></product></products><product currency="USD" name="Surf" price="1.30"><br /> <product currency="USD" name="Cheese" price="1.10"><br /> <product currency="USD" name="White Bread" price="1.90"><br /> <product currency="USD" name="Brown Bread" price="1.07"><br /> <product currency="USD" name="Dozen Eggs" price="1.14"><br /></product></product></product></product></product></products><br /><br />
and sample users:<br /><br /><br />
<users><br /> <user currency="USD" firstname="Alex" lastname="Ridriguez"><br /> <bought-product name="Surf"><br /> <bought-product name="Cheese"><br /> <friends-with lastname="Goodwin"><br /> <friends-with lastname="Doe"><br /> <friends-with lastname="Jennings"><br /> </friends-with></friends-with></friends-with></bought-product></bought-product></user><br /> <user currency="USD" firstname="Steve" lastname="Goodwin"><br /> <bought-product name="Cheese"><br /> <bought-product name="Brown Bread"><br /> </bought-product></bought-product></user><br /> <user currency="USD" firstname="John" lastname="Rodrigo"><br /> <bought-product name="White Bread"><br /> </bought-product></user><br /> <user currency="USD" firstname="George" lastname="Hortardo"><br /> <bought-product name="White Bread"><br /> <bought-product name="Dozen Eggs"><br /> </bought-product></bought-product></user><br /> <user currency="USD" firstname="Jane" lastname="Doe"><br /> <friends-with lastname="Goodwin"><br /> </friends-with></user><br /> <user currency="USD" firstname="Peter" lastname="Jennings"><br /> <friends-with lastname="Doe"><br /> </friends-with></user></users><users><user currency="USD" firstname="Alex" lastname="Ridriguez"><bought-product name="Surf"><bought-product name="Cheese"><friends-with lastname="Goodwin"><friends-with lastname="Doe"><friends-with lastname="Jennings"></friends-with></friends-with></friends-with></bought-product></bought-product></user><user currency="USD" firstname="Steve" lastname="Goodwin"><bought-product name="Cheese"><bought-product name="Brown Bread"></bought-product></bought-product></user><user currency="USD" firstname="John" lastname="Rodrigo"><bought-product name="White Bread"></bought-product></user><user currency="USD" firstname="George" lastname="Hortardo"><bought-product name="White Bread"><bought-product name="Dozen Eggs"></bought-product></bought-product></user><user currency="USD" firstname="Jane" lastname="Doe"><friends-with lastname="Goodwin"></friends-with></user><user currency="USD" firstname="Peter" lastname="Jennings"><friends-with lastname="Doe"></friends-with></user></users>
With this set up, I was able to answer the challenge and produce a web interface to browse users, user's friends, products and the user's products.
The Java source is available here:
github.com:sprind-data-neo4j-fun
and the database can be viewed here :
challenge demo (embdedded graph db)
Please not that this code is NOT production ready;It was done in a day and a half.
Next step is to implement this solution using Mongo DB as the back end.
