-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #342 from softeerbootcamp-2nd/feat/recommend
추천 알고리즘 구현 및 flask 웹서버로 http통신 구현
- Loading branch information
Showing
7 changed files
with
154 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from flask import Flask, request | ||
import recommend | ||
|
||
app = Flask(__name__) | ||
|
||
@app.route('/recommend/apriori', methods=['POST']) | ||
def apriori(): | ||
data = request.get_json() | ||
return recommend.recByApriori(data) | ||
|
||
if __name__ == '__main__': | ||
app.run(port=5001, debug=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import pandas as pd | ||
from mlxtend.preprocessing import TransactionEncoder | ||
from mlxtend.frequent_patterns import apriori, fpgrowth | ||
from mlxtend.frequent_patterns import association_rules | ||
import pymysql | ||
import time | ||
import os | ||
from dotenv import load_dotenv | ||
|
||
load_dotenv(verbose=True) | ||
|
||
conn = pymysql.connect(host=os.getenv('host'), user=os.getenv('user'), password=os.getenv('password'), db=os.getenv('db')) | ||
cur = conn.cursor() | ||
|
||
def recByApriori(body): | ||
start = time.time() | ||
carId = int(body['carId']) | ||
powerTrainId = int(body['powerTrain']) | ||
bodyTypeId = int(body['bodyType']) | ||
operationId = int(body['operation']) | ||
|
||
input = [] | ||
|
||
optionList = body['options'] | ||
|
||
for i in range(len(optionList)): | ||
input.append(optionList[i]['subOptionId']) | ||
|
||
input = set(input) | ||
dataset = [] | ||
cur.execute('SELECT hm.history_id, sh.sold_count, sh.sold_options_id FROM SalesHistory sh INNER JOIN HistoryModelMapper hm ON sh.history_id = hm.history_id WHERE sh.car_id = %s AND hm.model_id IN (%s, %s, %s) GROUP BY hm.history_id HAVING COUNT(DISTINCT hm.model_id) = 3;', (carId, powerTrainId, bodyTypeId, operationId)) | ||
dbRow = cur.fetchall() | ||
for j in range(len(dbRow)): | ||
oneRow = dbRow[j][2] | ||
if(oneRow == ''): | ||
continue | ||
options = oneRow.split(",") | ||
for i in range(int(dbRow[j][1])): | ||
dataset.append(options) | ||
|
||
start = time.time() | ||
te = TransactionEncoder() | ||
te_ary = te.fit(dataset).transform(dataset) | ||
df = pd.DataFrame(te_ary, columns=te.columns_) | ||
frequent_itemsets = fpgrowth(df, min_support=0.05, use_colnames=True) | ||
|
||
result_itemsets = association_rules(frequent_itemsets, metric="confidence", min_threshold=0.05) | ||
matching_itemsets = {} | ||
|
||
consequent_results = set() | ||
|
||
for idx, row in result_itemsets.iterrows(): | ||
confidence = row.confidence | ||
|
||
if set(row.antecedents).issubset(input) and len(row.consequents) <= 2 and not set(row.antecedents).union(set(row.consequents)).issubset(input): | ||
key = tuple(row.consequents) | ||
if key not in matching_itemsets or confidence > matching_itemsets[key]: | ||
matching_itemsets[key] = confidence | ||
|
||
sorted_items = sorted(matching_itemsets.items(), key=lambda x: x[1], reverse=True) | ||
top_items = sorted_items[:4] | ||
top_consequents = [consequent for consequent, _ in top_items] | ||
return top_consequents |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Invalid Access |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
backend/src/main/java/autoever2/cartag/controller/RecommendController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package autoever2.cartag.controller; | ||
|
||
import autoever2.cartag.service.RecommendService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequestMapping("/api/recommend") | ||
@RequiredArgsConstructor | ||
public class RecommendController { | ||
|
||
private final RecommendService recommendService; | ||
|
||
@PostMapping("/list") | ||
public String getRecommendedList() { | ||
return recommendService.getList(); | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
backend/src/main/java/autoever2/cartag/service/RecommendService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package autoever2.cartag.service; | ||
|
||
import org.json.simple.JSONArray; | ||
import org.json.simple.JSONObject; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.net.URI; | ||
import java.net.http.HttpClient; | ||
import java.net.http.HttpRequest; | ||
import java.net.http.HttpResponse; | ||
|
||
@Service | ||
public class RecommendService { | ||
|
||
@Value("${python.url") | ||
private String requestURL; | ||
|
||
//TODO: 응답 존재 안할 시 예외처리 | ||
public String getList() { | ||
HttpClient client = HttpClient.newHttpClient(); | ||
HttpRequest request = HttpRequest.newBuilder() | ||
.uri(URI.create(requestURL)) | ||
.POST(HttpRequest.BodyPublishers.ofString(getJsonFromEstimate())).build(); | ||
|
||
try { | ||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | ||
String body = response.body(); | ||
return body; | ||
} catch (Exception e) { | ||
e.getMessage(); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
public String getJsonFromEstimate() { | ||
JSONObject jsonObject = new JSONObject(); | ||
jsonObject.put("carId", 1); | ||
jsonObject.put("powerTrain", 1); | ||
jsonObject.put("bodyType", 3); | ||
jsonObject.put("operation", 5); | ||
|
||
JSONArray jsonArray = new JSONArray(); | ||
JSONObject subOption = new JSONObject(); | ||
subOption.put("subOptionId", 69); | ||
jsonArray.add(subOption); | ||
subOption.put("subOptionId", 70); | ||
jsonArray.add(subOption); | ||
|
||
jsonObject.put("options", jsonArray); | ||
|
||
|
||
return jsonObject.toJSONString(); | ||
} | ||
} |