Using jess with java, I'm creating a movie recommender expert system, it relies on information about the user like his/her preferred genre, his/her age, and the movies he/she has downloaded, I'm looking to add more sources of information (like the lead actors and directors of movies) to help me end up with the four best recommendations my system can come up with...
here is my code so far:
(deftemplate User
(declare (from-class User)))
(deftemplate Movie
(declare (from-class Movie)))
(deftemplate Download
(declare (from-class Download)))
(deftemplate Recommendation
(declare (from-class Recommendation)))
(deftemplate similar
(slot movieId1)
(slot movieId2))
(defrule find-similar
?movie1<-(Movie (movieId ?id1)(movieGenre ?genre))
?movie2<-(Movie (movieId ?id2&:(<> ?id2 ?id1))(movieGenre ?genre))
=>
(assert (similar (movieId1 ?id1) (movieId2 ?id2))))
(defrule recommend-movie-based-on-user-genre
"Recommends movies that has the same genre the user prefers."
(User (userId ?userId) (preferredGenre ?genre))
(Movie (movieId ?movieId) (movieGenre ?genre))
(not (Download (userId ?userId) (movieId ?movieId)))
(not (Recommendation (userId ?userId) (movieId ?movieId)))
=>
(add (new Recommendation ?userId ?movieId)))
(defrule recommend-movie-based-on-downloads
"Recommends movies similar to the ones the user has downloaded."
(Download (userId ?userId) (movieId ?movieId))
(similar (movieId1 ?movieId) (movieId2 ?movieId2))
(not (Download (userId ?userId) (movieId ?movieId2)))
(not (Recommendation (userId ?userId) (movieId ?movieId2)))
=>
(add (new Recommendation ?userId ?movieId2)))
my question is: how do I combine my different rules, in a way that makes my system capable of combining the information it's learned from each individual rule, and using that accumulated knowledge to come up with a "perfect" recommendation
First, you have to understand that there's a difference between basing recommendations on emperical data and basing recommendations on ad hoc methods.
An empirical based recommendation would be "80% of people gave movie X a thumbs up" or "You liked movie Y and 80% of people who liked movie Y also liked movie X" or "on average, people rated this movie 4 out of 5 stars".
An ad hoc recommendation is something you make up. For example, based on matching 4 of 5 specified criteria your program gives a movie a recommendation of 80%.
You're not using empirical data in your program, so it's up to you to determine the strength of a recommendation based on your criteria. A google search on "recommendation expert systems" or "movie recommendation expert systems" will give you some ideas on various ad hoc methods.
Here's an ad hoc method in CLIPS for combining recommendation weights (from 0 to 100):
CLIPS> (clear)
CLIPS>
(deftemplate recommendation
(slot movie)
(slot weight)
(multislot reasons))
CLIPS>
(defrule combine-weights
?rec1 <- (recommendation (movie ?movie)
(reasons $?reasons1)
(weight ?w1))
?rec2 <- (recommendation (movie ?movie)
(reasons $?reasons2&~$?reasons1)
(weight ?w2&:(<= ?w2 ?w1)))
=>
(retract ?rec2)
(modify ?rec1 (weight (/ (- (* 100 (+ ?w1 ?w2)) (* ?w1 ?w2)) 100))
(reasons ?reasons1 ?reasons2)))
CLIPS>
(assert (recommendation (movie "Aliens") (weight 80) (reasons genre)))
<Fact-1>
CLIPS>
(assert (recommendation (movie "Aliens") (weight 60) (reasons downloads)))
<Fact-2>
CLIPS>
(agenda)
0 combine-weights: f-1,f-2
For a total of 1 activation.
CLIPS> (watch facts)
CLIPS> (run)
<== f-2 (recommendation (movie "Aliens") (weight 60) (reasons downloads))
<== f-1 (recommendation (movie "Aliens") (weight 80) (reasons genre))
==> f-3 (recommendation (movie "Aliens") (weight 92.0) (reasons genre downloads))
CLIPS>