Skip to content

Commit 16719a8

Browse files
tqtgdarrylong
authored andcommitted
Update backend, frontend, sample data, readme, opensearch schema
1 parent 0886ace commit 16719a8

File tree

26 files changed

+649
-127
lines changed

26 files changed

+649
-127
lines changed

README.md

Lines changed: 97 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ Cornac is endorsed by ACM RecSys for evaluating and reproducing recommendation a
2727
The architecture consists of the following components:
2828

2929
1. **Cornac-AB Backend Server** ([Backend source code](backend)): Handles API endpoints and business logic.
30-
2. **Cornac-AB Frontend** ([Frontend source code](frontend)): Offers a user interface for interacting with the A/B tests.
31-
3. **Books-AB User Interaction Frontend** ([User Interaction Frontend source code](democlient)): Provides a frontend for user interactions.
30+
2. **Books-AB User Interaction Frontend** ([User Interaction Frontend source code](democlient)): Provides a frontend for user interactions.
31+
3. **Cornac-AB Frontend** ([Frontend source code](frontend)): Offers a user interface to setup, track and evaluate models for the A/B tests.
3232
4. **OpenSearch & OpenSearch Dashboards** ([Official site](https://opensearch.org)): Data indexing, search, and visualization.
3333
5. **GoodReads 10k Dataset** ([Goodbooks-10k repository](https://github.com/zygmuntz/goodbooks-10k)): Preloaded data for demonstration purposes.
3434

@@ -40,15 +40,92 @@ docker compose up
4040
```
4141
This command will start all the required components and load the GoodReads dataset into OpenSearch for A/B testing and visualization.
4242

43-
## Accessing the Solution
43+
## Usage Guide
44+
45+
### Accessing the Solution
4446

4547
Once the containers are running, you can access the various parts of the solution via the following URLs:
46-
- Cornac-AB Backend Server `localhost:8080`
47-
- Cornac-AB Frontend `localhost:8081`
48-
- Books-AB User Interaction Frontend `localhost:8082`
48+
- [Books-AB User Interaction Frontend](#2) `localhost:8082`
49+
- [Cornac-AB Frontend]() `localhost:8081`
4950
- OpenSearch API `localhost:9200`
5051
- OpenSearch Dashboards `localhost:5601`
5152

53+
### 1. Cornac-AB Backend
54+
55+
This backend server is built on [Spring](https://spring.io/). Spring is a production grade scalable framework for building web applications.
56+
57+
This solution connects to a local h2 database (which could be easily replaceable with most SQL databases supported by Spring).
58+
59+
[Cornac instances](https://cornac.readthedocs.io/en/stable/user/iamadeveloper.html#running-an-api-service) (Based on Flask) are run on this container, and restarts automatically should it be found to be down.
60+
61+
The [Spring Data OpenSearch](https://github.com/opensearch-project/spring-data-opensearch) library has been used to connect the backend to the OpenSearch service.
62+
63+
### 2. Books-AB User Interaction Frontend
64+
65+
#### Accessing the frontend
66+
http://localhost:8082/
67+
68+
Included in this solution is a sample frontend that showcases how the solution receives user interactions.
69+
70+
#### A. Selecting a User ID
71+
72+
<img src="screenshots/demo-1.png" alt="demo" width="500"/>
73+
74+
Users will first enter their User ID. To decrease the size of the sample data, we only included past book history data of user IDs 100-199.
75+
76+
#### B. Viewing Books Recommendations
77+
<img src="screenshots/demo-2.png" alt="demo" width="500"/>
78+
79+
Click **Explore Books**. A particular model is allocated by the backend, which provides recommendations as on this explore page. Recommendation records are stored in OpenSearch as well.
80+
81+
#### C. Providing Book Feedback
82+
Users could select to view more details by clicking on them.
83+
84+
<img src="screenshots/demo-3.png" alt="demo" width="500"/>
85+
86+
When a user clicks on a book, we register that as a feedback. This feedback will be attributed with the **click** action on OpenSearch.
87+
88+
<img src="screenshots/demo-4.png" alt="demo" width="500"/>
89+
90+
Further in this view, users will be able to rate the book by click the stars icon, which will be attributed with a **rate** action as a feedback on OpenSearch.
91+
92+
#### D. Viewing User Interactions
93+
94+
95+
User interaction in this frontend will be recorded in OpenSearch as **recommendations** and **feedbacks**. These can be viewed in the Cornac-AB frontend dashboards in real-time, as shown in the next section.
96+
97+
#### 3. Cornac-AB Frontend
98+
99+
#### Accessing the frontend
100+
http://localhost:8081/
101+
102+
<img src="screenshots/frontend-1.png" alt="demo" width="500"/>
103+
104+
You'll be welcomed with this screen.
105+
106+
#### A. Viewing the Dashboards
107+
108+
<img src="screenshots/frontend-2.png" alt="demo" width="500"/>
109+
110+
Going to the dashboard screen will show you multiple dashboards, including the Users, Recommendations and Feedback dashboards. Sample data based on the Goodbooks 10k dataset has already been generated and inserted for you.
111+
112+
#### B. Evaluating your Models
113+
<img src="screenshots/frontend-3.png" alt="demo" width="500"/>
114+
115+
Under the Feedback Dashboard section, you will be able to filter data, and further compare your models using the Cornac evaluation features by selecting the **Run Cornac Evaluation** button.
116+
117+
<img src="screenshots/frontend-4.png" alt="demo" width="500"/>
118+
119+
A summary of the data that will be put through Cornac's evaluation services will be shown. You could add more metrics by selecting the **Add Metric** button will allow you to add more metrics as shown below.
120+
121+
<img src="screenshots/frontend-5.png" alt="demo" width="300"/>
122+
123+
#### C. Viewing Evaluation Results
124+
125+
<img src="screenshots/frontend-6.png" alt="demo" width="500"/>
126+
127+
You will then be shown with the metric results, along with the p-values of individual models to evaluate the performance of your models.
128+
52129
## Further Usage
53130

54131
Cornac-AB is a solution which showcases how A/B Testing could be done and visualized as a forward testing experiment. Feel free to further contribute, or fork the repository and extend it to your own application needs.
@@ -61,6 +138,20 @@ This project welcomes contributions and suggestions. Before contributing, please
61138

62139
If you use Cornac in a scientific publication, we would appreciate citations to the following papers:
63140

141+
<details>
142+
<summary><a href="https://ieeexplore.ieee.org/abstract/document/9354572">Cornac-AB: An Open-Source Recommendation Framework with Native A/B Testing Integration</a>, Ong <i>et al.</i>, In Proceedings of the ACM Web Conference 2024.</summary>
143+
144+
```
145+
@inproceedings{ong2024cornacab,
146+
title={Cornac-AB: An Open-Source Recommendation Framework with Native A/B Testing Integration},
147+
author={Ong, Darryl and Truong, Quoc-Tuan and Lauw, Hady W},
148+
journal={Proceedings of the ACM Web Conference 2024},
149+
pages={xx--yy},
150+
year={2024}
151+
}
152+
```
153+
</details>
154+
64155
<details>
65156
<summary><a href="http://jmlr.org/papers/v21/19-805.html">Cornac: A Comparative Framework for Multimodal Recommender Systems</a>, Salah <i>et al.</i>, Journal of Machine Learning Research, 21(95):1–5, 2020.</summary>
66157

@@ -77,34 +168,6 @@ If you use Cornac in a scientific publication, we would appreciate citations to
77168
```
78169
</details>
79170

80-
<details>
81-
<summary><a href="https://ieeexplore.ieee.org/abstract/document/9354572">Exploring Cross-Modality Utilization in Recommender Systems</a>, Truong <i>et al.</i>, IEEE Internet Computing, 25(4):50–57, 2021.</summary>
82-
83-
```
84-
@article{truong2021exploring,
85-
title={Exploring Cross-Modality Utilization in Recommender Systems},
86-
author={Truong, Quoc-Tuan and Salah, Aghiles and Tran, Thanh-Binh and Guo, Jingyao and Lauw, Hady W},
87-
journal={IEEE Internet Computing},
88-
year={2021},
89-
publisher={IEEE}
90-
}
91-
```
92-
</details>
93-
94-
<details>
95-
<summary><a href="http://jmlr.org/papers/v21/19-805.html">Multi-Modal Recommender Systems: Hands-On Exploration</a>, Truong <i>et al.</i>, ACM Conference on Recommender Systems, 2021.</summary>
96-
97-
```
98-
@inproceedings{truong2021multi,
99-
title={Multi-modal recommender systems: Hands-on exploration},
100-
author={Truong, Quoc-Tuan and Salah, Aghiles and Lauw, Hady},
101-
booktitle={Fifteenth ACM Conference on Recommender Systems},
102-
pages={834--837},
103-
year={2021}
104-
}
105-
```
106-
</details>
107-
108171
## License
109172

110173
[Apache License 2.0](LICENSE)

backend/src/main/java/ai/preferred/cornac/entity/Feedback.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public class Feedback {
2626
private String userId;
2727
@Field(name="item_id", type = FieldType.Keyword)
2828
private String itemId;
29+
@Field(name="recommendation_id", type = FieldType.Keyword)
30+
private String recommendationId;
2931
private String model;
3032
private Integer rating;
3133
private String action; // 'click', 'rating'

backend/src/main/java/ai/preferred/cornac/entity/RecommendLog.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ public class RecommendLog {
2323
private String id;
2424
@Field(type = FieldType.Keyword)
2525
private Integer experimentId;
26-
@Field(type = FieldType.Keyword)
26+
@Field(name="user_id", type = FieldType.Keyword)
2727
private String userId;
2828
@Field(type = FieldType.Date, pattern = "uuuu-MM-dd'T'HH:mm:ss.SSSSSS||uuuu-MM-dd'T'HH:mm:ss.SSS||uuuu-MM-dd'T'HH:mm:ss||uuuu-MM-dd", format = {})
2929
private LocalDateTime timestamp;
3030
@Field(type = FieldType.Keyword)
3131
private List<String> recommendations;
32+
private String model;
3233

3334
private boolean isFallback;
3435
private String fallbackReason;

backend/src/main/java/ai/preferred/cornac/service/CornacService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,9 @@ public CornacEvaluationResponse postCornacInstanceEvaluation(CornacInstance corn
371371
.body(BodyInserters.fromValue(evaluationRequest))
372372
.retrieve()
373373
.bodyToMono(CornacEvaluationResponse.class)
374+
.doOnError(error -> {
375+
error.printStackTrace();
376+
})
374377
.block();
375378
}
376379

backend/src/main/java/ai/preferred/cornac/service/FeedbackService.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,15 @@ public Feedback addFeedback(String recommendId, String itemId, Integer rating, S
3636
UserAbAllocation userAbAllocation = userAbAllocationRepository.findByExperimentIdAndUserId(
3737
recommendLog.getExperimentId(), recommendLog.getUserId()
3838
);
39-
List<CornacInstance> cornacInstances = cornacInstanceRepository.findCornacInstanceByExperimentId(recommendLog.getExperimentId());
40-
41-
String cornacInstanceName;
42-
if (userAbAllocation == null) {
43-
cornacInstanceName = "unallocated";
44-
} else {
45-
cornacInstanceName = cornacInstances.get(userAbAllocation.getAbGroup()).getServiceName();
46-
}
4739

4840
Feedback feedback = new Feedback();
4941
feedback.setItemId(itemId);
5042
feedback.setRating(rating);
5143
feedback.setUserId(recommendLog.getUserId());
5244
feedback.setTimestamp(LocalDateTime.now());
5345
feedback.setExperimentId(recommendLog.getExperimentId());
54-
feedback.setModel(cornacInstanceName);
46+
feedback.setModel(recommendLog.getModel());
47+
feedback.setRecommendationId(recommendId);
5548
feedback.setAction(action);
5649

5750
return feedbackRepository.save(feedback);

backend/src/main/java/ai/preferred/cornac/service/RecommendService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ public RecommendLogDto getRecommendations(String userId, String k){
129129
log.setUserId(userId);
130130
log.setTimestamp(LocalDateTime.now());
131131
log.setRecommendations(recommendation.getRecommendations());
132+
log.setModel(cornacInstance == null ? "unallocated" : cornacInstance.getServiceName());
132133

133134
RecommendLog recommendLog = recommendLogRepository.save(log);
134135
return convertToRecommendLogDto(recommendLog);

0 commit comments

Comments
 (0)