Content Based recommender system 2 - UCM-GAIA/RecoLibry-Core GitHub Wiki
The complete example is implemented in the test2 of RecoLibry-Example repository.
In this section, we explain how to build a content-based recommender system with RecoLibry-Core. This example builds the recommender system using a configuration file. We will make a recommender system of movies. It will recommend movies with similar genres than a user profile. To build this recommender system, it is necessary to download the file movies.csv
form Movielens 100K dataset and insert it in your project.
The schema of our project will be as follow:
Next, we add the RecoLibry-Core in our project adding the dependency in our pom.xml
file. To remember that you can visit the Start section.
First, we are going to configure the recommender system. In this example, we use a JSON file to configure the recommender system. This file must contain two elements: generateClass
and configuration
.
{
"generateClass": {
...
},
"configure": [
...
]
}
In our example, we need to make an auxiliary class to save the movies information. For this reason, we must complete the generated method. This class will call MovieDescription
and should contain the next attributes based on the movies.csv
file:
-
id
: Movie identity number. It is anInteger
type. -
name
: Movie name. It is aString
value. -
genres
: List with genres of the movie. The list type isString
.
Then, we can add all this information to our configuration file. The two first attributes in generateClass
are the package that will contain the new class (packageName
) and the name of the class (className
):
"generateClass": {
"packageName": "com.recolibry.example.MoviesRecommender",
"className": "MovieDescription",
...
}
Next, we define the attributes included in our new class MovieDescription. These attributes are separated into two groups. The first group (attributes
) contains attributes with a simple data type (Integer
, Double
, Float
, String
or Boolean
). The second group (attributesList
) contains attributes with a list type. The list types must be also of these types. Then, we need to include each attribute in its corresponding list. For each attribute, we define the name
and the type
of this attribute:
"generateClass": {
...,
"attributes": [
{
"name": "id",
"type": "Integer"
},
{
"name": "title",
"type": "String"
}
],
"attributeList": [
{
"name": "genres",
"type": "String"
}
]
},
That is all the information that we need to make the auxiliary class. Next, we define the components used in our recommender system.
Next, we define which components are in our recommender system. To do that, we define what class or instance is used in our recommender system using the template explained in the configuration section.
Next, we configure the recommender algorithm. In this example, we will use the RecommenderJColibri
algorithm. This algorithm needs extra components: a connector and similarity functions. We start to define the connector. The movie's description is in CSV file. For this reason, we are going to configure a CSVConnector
. This connector needs 3 elements: a BeansFactory
to convert the CSV data in MoviesDescriptions
, the path of out file and a boolean
data that set if the CSV file contains a title row. We add these bindings in the list of configure
:
"configure": [
{
"type": "Instance",
"bind": "java.lang.String",
"annotated": "BeanClass",
"to": "com.recolibry.example.MoviesRecommender.MovieDescription"
},
{
"type": "Instance",
"bind": "java.lang.String",
"annotated": "fileName",
"to": "./data/movies.csv"
},
{
"type": "Instance",
"bind": "java.lang.Boolean",
"annotated": "existTitleRow",
"to": true
},
...
]
Now we have defined the components used by CSVConnector
. Next, we define to RecommenderJColibry
that we will use a CSVConnector
component:
"configure": [
...,
{
"type": "Class",
"bind": "es.ucm.fdi.gaia.jcolibri.cbrcore.Connector",
"annotated": null,
"to": "es.ucm.fdi.gaia.recolibry.implementations.jcolibri.CSVConnector"
},
...
]
The next elements that our recommender system needs are similarity functions. In JColibry there are 2 types of similarity functions: global similarity functions and local similarity functions. Global similarity functions return the similarity between 2 objects. On the other hand, local similarity functions return the similarity between 2 attributes with the same name in 2 objects. In our example, we will have a local similarity function to compare the movies genres respect the genres in the query. This similarity function is not included in jColibri. For this reason, we need to create this in a class called GenresSimilarity
. You can copy the next code in your new class:
public class GenresSimilarity implements LocalSimilarityFunction {
@Override
public double compute(Object caseObject, Object queryObject) throws NoApplicableSimilarityFunctionException {
List<String> caseGenres = (List<String>) caseObject;
List<String> queryGenres = (List<String>) queryObject;
double equal = 0;
double totalGenres = 0;
for(int i=0; i<caseGenres.size(); i++)
for(int j=0; j<queryGenres.size(); j++)
if (caseGenres.get(i).equals(queryGenres.get(j)))
equal++;
totalGenres = caseGenres.size() + queryGenres.size() - equal;
return equal / totalGenres;
}
public boolean isApplicable(Object caseObject, Object queryObject) {
if (caseObject != null && queryObject != null &&
caseObject instanceof List && queryObject instanceof List)
return true;
else
return false;
}
}
This class will be our local similarity function to compare genres. To add local similarities functions in our recommender system, In the configure section, you can copy the template to define a local similarity function. Now, we add the new local similarity function in our configuration:
"configure": [
...,
{
"type": "LocalSimilarity",
"bind": "LocalSimilarityConfiguration",
"annotated": null,
"to": null,
"similarities": [{
"attribute": "genres",
"class": "com.recolibry.example.MoviesRecommender.MovieDescription",
"similarities": "com.recolibry.example.MoviesRecommender.GenresSimilarity"
}]
}
]
In addition, we must define which global similarity function we will use. In this case, we will use the class Average
from jColibri:
"configure": [
{
"type": "Class",
"bind": "es.ucm.fdi.gaia.jcolibri.method.retrieve.NNretrieval.similarity.GlobalSimilarityFunction",
"annotated": null,
"to": "es.ucm.fdi.gaia.jcolibri.method.retrieve.NNretrieval.similarity.global.Average"
},
]
The last element that we need to include in our recommender algorithm is how many results we want to recover. To do that, we bind the number of results using the N-Results
property. Our example will return 10 results:
"configure": [
...,
{
"type": "Instance",
"bind": "java.lang.Integer",
"annotated": "N-Results",
"to": 10
},
...
]
At this moment, we have all the components for the recommender algorithm. The next step is to define which algorithm we will use in the recommender system. To do that, we set the RecommenderJColibry
class as our recommender algorithm:
"configure": [
...,
{
"type": "Class",
"bind": "es.ucm.fdi.gaia.recolibry.api.RecommenderAlgorithm",
"annotated": null,
"to": "es.ucm.fdi.gaia.recolibry.implementations.jcolibri.RecommenderJColibri"
}
]
Finally, we need to define the Query
for our recommender system. In our case, the query will be a QueryJColibri
:
"configure": [
...,
{
"type": "Class",
"bind": "es.ucm.fdi.gaia.recolibry.api.Query",
"annotated": null,
"to": "es.ucm.fdi.gaia.recolibry.implementations.jcolibri.QueryJColibri"
}
]
We complete all the configuration of our recommender system. If you need to check your configuration, in the RecoLibry-Examples repository you have the complete configuration. Next, we can create a new instance of our recommender system.
For the next steps, we will create a new class called Main. This class will contain a static method to get an instance of our recommender system and the main method to execute it:
public class Main {
public static RecommenderSystem getRecommender() {
}
public static void main(String[] args) {
}
}
In this section, we will complete the method to obtain an instance of the system. We create the recommender system using the RecommenderSystemFactory
. To do that, we call the method makeRecommenderByJson()
with the path of our configuration file. Finally, we return the system created:
public static RecommenderSystem getRecommenderSystem() {
//Make new instance of recommender system
RecommenderSystemFactory factory = new RecommenderSystemFactory();
factory.makeRecommenderByJson(System.getProperty("user.dir") + "/configurations/configuration.json");
// Return recommender system
return factory.getRecommender();
}
Now, we can execute our recommender system.
In this section, we explain how to use the recommender system created before. In this example, we will ask our system which movies recommend to a user who likes the genres: Adventure, Fantasy, and Children.
First, we call the method to obtain the recommender system that we will execute. Next, we call the method getQuery()
in our recommender system. It returns the query object that can use in our system:
public static void main(String[] args) {
//Get recommender system
RecommenderSystem recSys = getRecommenderSystem();
//Get query object
Query query = recSys.getQuery();
...
}
Next, we need to prepare our query before to execute in our recommender system. To do that, we call the query method initialize()
. After that, we add the genres
of the user in the attribute genre of MovieDescription
:
public static void main(String[] args) {
...
//Initialize query
query.initialize();
//Add genres in our query
String[] genresArray = new String[]{"Adventure", "Children", "Fantasy"};
List<String> genres = new ArrayList<>(Arrays.asList(genresArray));
query.setAttributeValue("genres", genres);
...
}
At this moment, our query contains all information and we can send it to the recommender system. Before executing the recommender system, we must call the function initRecommender()
. Next, we execute the method recommend()
with the query object completed before. Finally, if we don't need to execute the recommender system again, we can finish its execution calling the method closeRecommender()
. Our example has the next instructions:
public static void main(String[] args) {
...
//Initialize recommender system
recSys.initRecommender();
//Get recommendations from query
List<RecommenderResult> results = recSys.recommend(query);
// Close recommender system
recSys.closeRecommender();
...
}
Finally, we print the result of our recommender system:
public static void main(String[] args) {
...
// Print the result of recommender system
for(RecommenderResult r : results)
System.out.println(r);
}