├── README.md ├── SearchAds.proto ├── AdsSelector.java ├── hw1.md └── MySQLAccess.java /README.md: -------------------------------------------------------------------------------- 1 | # CS504 后端工程师直通车 2 | 3 | ## FAQ 4 | [请前往Issue页面查看FAQ](https://github.com/BitTigerInst/BitTiger-CS504-FAQ/issues) 5 | 6 | ## Homework 7 | - [hw1](https://github.com/BitTigerInst/BitTiger-CS504-FAQ/blob/master/hw1.md) 8 | -------------------------------------------------------------------------------- /SearchAds.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "io.bittiger.adindex"; 5 | option java_outer_classname = "SearchAds"; 6 | option objc_class_prefix = "ADS"; 7 | 8 | package adindex; 9 | 10 | // The greeting service definition. 11 | service AdsIndex { 12 | // Sends a greeting 13 | rpc GetAds (AdsRequest) returns (AdsReply) {} 14 | } 15 | 16 | message Query { 17 | repeated string term = 1; 18 | } 19 | 20 | message Ad { 21 | int64 adId = 1; 22 | int64 campaignId = 2; 23 | repeated string keyWords = 3; 24 | double relevanceScore = 4; 25 | double pClick = 5; 26 | double bidPrice = 6; 27 | double rankScore = 7; 28 | double qualityScore = 8; 29 | double costPerClick = 9; 30 | int32 position = 10;//1: top , 2: bottom 31 | string title = 11; // required 32 | double price = 12; // required 33 | string thumbnail = 13; // required 34 | string description = 14; // required 35 | string brand = 15; // required 36 | string detail_url = 16; // required 37 | string query = 17; //required 38 | string category = 18; 39 | } 40 | 41 | message AdsRequest { 42 | repeated Query query = 1; 43 | } 44 | 45 | // The response message containing the greetings 46 | message AdsReply { 47 | repeated Ad ad = 1; 48 | } 49 | -------------------------------------------------------------------------------- /AdsSelector.java: -------------------------------------------------------------------------------- 1 | package io.bittiger.adindex; 2 | import java.io.IOException; 3 | import java.net.InetSocketAddress; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Set; 8 | import net.spy.memcached.AddrUtil; 9 | import net.spy.memcached.ConnectionFactoryBuilder; 10 | import net.spy.memcached.FailureMode; 11 | import net.spy.memcached.MemcachedClient; 12 | 13 | 14 | public class AdsSelector { 15 | private static AdsSelector instance = null; 16 | //private int EXP = 7200; 17 | private String mMemcachedServer; 18 | private int mMemcachedPortal; 19 | private String mysql_host; 20 | private String mysql_db; 21 | private String mysql_user; 22 | private String mysql_pass; 23 | MemcachedClient cache; 24 | 25 | protected AdsSelector(String memcachedServer,int memcachedPortal,String mysqlHost,String mysqlDb,String user,String pass) 26 | { 27 | mMemcachedServer = memcachedServer; 28 | mMemcachedPortal = memcachedPortal; 29 | mysql_host = mysqlHost; 30 | mysql_db = mysqlDb; 31 | mysql_user = user; 32 | mysql_pass = pass; 33 | String address = mMemcachedServer + ":" + mMemcachedPortal; 34 | try { 35 | cache = new MemcachedClient(new ConnectionFactoryBuilder().setDaemon(true).setFailureMode(FailureMode.Retry).build(), AddrUtil.getAddresses(address)); 36 | }catch (IOException e) { 37 | // TODO Auto-generated catch block 38 | e.printStackTrace(); 39 | } 40 | } 41 | public static AdsSelector getInstance(String memcachedServer,int memcachedPortal,String mysqlHost,String mysqlDb,String user,String pass) { 42 | if(instance == null) { 43 | instance = new AdsSelector(memcachedServer, memcachedPortal,mysqlHost,mysqlDb,user,pass); 44 | } 45 | return instance; 46 | } 47 | public List selectAds(Query query) 48 | { 49 | List adList = new ArrayList(); 50 | HashMap matchedAds = new HashMap(); 51 | try { 52 | for(int i = 0; i < query.getTermList().size();i++) 53 | { 54 | String queryTerm = query.getTerm(i); 55 | System.out.println("selectAds queryTerm = " + queryTerm); 56 | @SuppressWarnings("unchecked") 57 | Set adIdList = (Set)cache.get(queryTerm); 58 | if(adIdList != null && adIdList.size() > 0) 59 | { 60 | for(Object adId : adIdList) 61 | { 62 | Long key = (Long)adId; 63 | if(matchedAds.containsKey(key)) 64 | { 65 | int count = matchedAds.get(key) + 1; 66 | matchedAds.put(key, count); 67 | } 68 | else 69 | { 70 | matchedAds.put(key, 1); 71 | } 72 | } 73 | } 74 | } 75 | for(Long adId:matchedAds.keySet()) 76 | { 77 | System.out.println("selectAds adId = " + adId); 78 | MySQLAccess mysql = new MySQLAccess(mysql_host, mysql_db, mysql_user, mysql_pass); 79 | Ad.Builder ad = mysql.getAdData(adId); 80 | double relevanceScore = matchedAds.get(adId) * 1.0 / ad.getKeyWordsList().size(); 81 | System.out.println("relevanceScore = " + relevanceScore); 82 | ad.setRelevanceScore(relevanceScore); 83 | System.out.println("selectAds pClick = " + ad.getPClick()); 84 | System.out.println("selectAds relevanceScore = " + ad.getRelevanceScore()); 85 | adList.add(ad.build()); 86 | } 87 | } catch (IOException e) { 88 | // TODO Auto-generated catch block 89 | e.printStackTrace(); 90 | } catch (Exception e) { 91 | // TODO Auto-generated catch block 92 | e.printStackTrace(); 93 | } 94 | 95 | return adList; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /hw1.md: -------------------------------------------------------------------------------- 1 | # 实现 RunningInformationAnalysisService 2 | 3 | 功能要求: 4 | 每一个`RunningInformation`都包含 5 | ``` 6 | runningId, 7 | latitude, 8 | longitude, 9 | runningDistance, 10 | totalRunningTime, 11 | heartRate, 12 | Timestamp, 13 | userInfo 14 | ``` 15 | 16 | 其中`userInfo`包含了 17 | ``` 18 | username, 19 | address 20 | ``` 21 | 22 | `HearRate`初始值为0,要求当数据插入数据库时候生成一个60-200中间的随机数 23 | 24 | ## 要求 25 | 1. `RunningInformation` 存储在`private` 表里 26 | 27 | 2. 要求设计REST API 能够返回符合如下条件的JSON Response: 28 | ``` 29 | { 30 |    "runningId": "7c08973d-bed4-4cbd-9c28-9282a02a6032", 31 |    "totalRunningTime": 2000, 32 |    “heartRate”: 75, 33 |    “userId”: 1, 34 |    "userName": "Ross", 35 |    "userAddress": "504 CS Street, Mountain View, CA 88888", 36 |    "healthWarningLevel": HIGH 37 | } 38 | ``` 39 | 40 | 3. 要求返回结果按照`healthWarningLevel`从高到低进行排列,每页显示两个数据 41 | 42 | >**提示** 43 | >`HealthWarningLevel`由`heartRate`大小决定 44 | > - 如果heartRate>=60 && <=75 healthWarningLevel = “LOW” 45 | > - 如果heartRate>75 && <=120 healthWarningLevel = “NORMAL” 46 | > - 如果heartRate>120 healthWarningLevel = “HIGH” 47 | 48 | 4. REST API能支持delete by running ID 操作 49 | 50 | 5. 数据库要求用MySQL实现 51 | 52 | ## JSON输入 53 | ``` 54 | [ 55 |  { 56 |    "runningId": "7c08973d-bed4-4cbd-9c28-9282a02a6032", 57 |    "latitude": "38.9093216", 58 |    "longitude": "-77.0036435", 59 |    "runningDistance": "39492", 60 |    "totalRunningTime": "2139.25", 61 |    "heartRate": 0, 62 |    "timestamp": "2017-04-01T18:50:35Z", 63 |    "userInfo": { 64 |      "username": "ross0", 65 |      "address": "504 CS Street, Mountain View, CA 88888" 66 |    } 67 |  }, 68 |  { 69 |    "runningId": "07e8db69-99f2-4fe2-b65a-52fbbdf8c32c", 70 |    "latitude": "39.927434", 71 |    "longitude": "-76.635816", 72 |    "runningDistance": "1235", 73 |    "totalRunningTime": "3011.23", 74 |    "heartRate": 0, 75 |    "timestamp": "2017-04-01T18:50:35Z", 76 |    "userInfo": { 77 |      "username": "ross1", 78 |      "address": "504 CS Street, Mountain View, CA 88888" 79 |    } 80 |  }, 81 |  { 82 |    "runningId": "2f3c321b-d239-43d6-8fe0-c035ecdff232", 83 |    "latitude": "40.083824", 84 |    "longitude": "-76.098019", 85 |    "runningDistance": "23567", 86 |    "totalRunningTime": "85431.23", 87 |    "heartRate": 0, 88 |    "timestamp": "2017-04-01T18:50:35Z", 89 |    "userInfo": { 90 |      "username": "ross2", 91 |      "address": "504 CS Street, Mountain View, CA 88888" 92 |    } 93 |  }, 94 |  { 95 |    "runningId": "28810a26-25e6-4680-8baf-59bb07c4aee0", 96 |    "latitude": "42.957466", 97 |    "longitude": "-76.344201", 98 |    "runningDistance": "11135", 99 |    "totalRunningTime": "98965", 100 |    "heartRate": 0, 101 |    "timestamp": "2017-04-01T18:50:35Z", 102 |    "userInfo": { 103 |      "username": "ross3", 104 |      "address": "504 CS Street, Mountain View, CA 88888" 105 |    } 106 |  }, 107 |  { 108 |    "runningId": "fb0b4725-ac25-4812-b425-d43a18c958bb", 109 |    "latitude": "38.5783821", 110 |    "longitude": "-77.3242436", 111 |    "runningDistance": "231", 112 |    "totalRunningTime": "123", 113 |    "heartRate": 0, 114 |    "timestamp": "2017-04-01T18:50:35Z", 115 |    "userInfo": { 116 |      "username": "ross4", 117 |      "address": "504 CS Street, Mountain View, CA 88888" 118 |    } 119 |  }, 120 |  { 121 |    "runningId": "35be446c-9ed1-4e3c-a400-ee59bd0b6872", 122 |    "latitude": "42.375786", 123 |    "longitude": "-76.870872", 124 |    "runningDistance": "0", 125 |    "totalRunningTime": "0", 126 |    "heartRate": 0, 127 |    "timestamp": "2017-04-01T18:50:35Z", 128 |    "userInfo": { 129 |      "username": "ross5", 130 |      "address": "504 CS Street, Mountain View, CA 88888" 131 |    } 132 |  }, 133 |  { 134 |    "runningId": "15dfe2b9-e097-4899-bcb2-e0e8e72416ad", 135 |    "latitude": "40.2230391039276", 136 |    "longitude": "-76.0626631118454", 137 |    "runningDistance": "0.1", 138 |    "totalRunningTime": "0.1", 139 |    "heartRate": 0, 140 |    "timestamp": "2017-04-01T18:50:35Z", 141 |    "userInfo": { 142 |      "username": "ross6", 143 |      "address": "504 CS Street, Mountain View, CA 88888" 144 |    } 145 |  } 146 | ] 147 | ``` 148 | -------------------------------------------------------------------------------- /MySQLAccess.java: -------------------------------------------------------------------------------- 1 | package io.bittiger.adindex; 2 | import java.sql.Connection; 3 | import java.sql.DriverManager; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | 8 | 9 | 10 | public class MySQLAccess { 11 | private Connection d_connect = null; 12 | private String d_user_name; 13 | private String d_password; 14 | private String d_server_name; 15 | private String d_db_name; 16 | public void close() throws Exception { 17 | System.out.println("Close database"); 18 | try { 19 | if (d_connect != null) { 20 | d_connect.close(); 21 | } 22 | } catch (Exception e) { 23 | throw e; 24 | } 25 | } 26 | 27 | public MySQLAccess(String server,String db,String user,String password) { 28 | d_server_name = server; 29 | d_db_name = db; 30 | d_user_name = user; 31 | d_password = password; 32 | } 33 | 34 | private Connection getConnection() throws Exception { 35 | try { 36 | // This will load the MySQL driver, each DB has its own driver 37 | Class.forName("com.mysql.jdbc.Driver"); 38 | String conn = "jdbc:mysql://" + d_server_name + "/" + 39 | d_db_name+"?user="+d_user_name+"&password="+d_password; 40 | System.out.println("Connecting to database: " + conn); 41 | d_connect = DriverManager.getConnection(conn); 42 | System.out.println("Connected to database"); 43 | return d_connect; 44 | } catch(Exception e) { 45 | throw e; 46 | } 47 | } 48 | 49 | private Boolean isRecordExist(Connection connect,String sql_string) throws SQLException { 50 | PreparedStatement existStatement = null; 51 | boolean isExist = false; 52 | 53 | try 54 | { 55 | existStatement = connect.prepareStatement(sql_string); 56 | ResultSet result_set = existStatement.executeQuery(); 57 | if (result_set.next()) 58 | { 59 | isExist = true; 60 | } 61 | } 62 | catch(SQLException e ) 63 | { 64 | System.out.println(e.getMessage()); 65 | throw e; 66 | } 67 | finally 68 | { 69 | if (existStatement != null) 70 | { 71 | existStatement.close(); 72 | }; 73 | } 74 | 75 | return isExist; 76 | } 77 | 78 | 79 | public Ad.Builder getAdData(Long adId) throws Exception { 80 | Connection connect = null; 81 | PreparedStatement adStatement = null; 82 | ResultSet result_set = null; 83 | Ad.Builder ad = Ad.newBuilder(); 84 | String sql_string = "select * from " + d_db_name + ".ad where adId=" + adId; 85 | try { 86 | connect = getConnection(); 87 | adStatement = connect.prepareStatement(sql_string); 88 | result_set = adStatement.executeQuery(); 89 | while (result_set.next()) { 90 | ad.setAdId(result_set.getLong("adId")); 91 | ad.setCampaignId(result_set.getLong("campaignId")); 92 | String keyWords = result_set.getString("keyWords"); 93 | String[] keyWordsList = keyWords.split(","); 94 | for(int index = 0; index < keyWordsList.length; index++) { 95 | ad.addKeyWords(keyWordsList[index]); 96 | } 97 | ad.setBidPrice(result_set.getDouble("bidPrice")); 98 | ad.setPrice(result_set.getDouble("price")); 99 | ad.setThumbnail(result_set.getString("thumbnail")); 100 | ad.setDescription(result_set.getString("description")); 101 | ad.setBrand(result_set.getString("brand")); 102 | ad.setDetailUrl(result_set.getString("detail_url")); 103 | ad.setCategory(result_set.getString("category")); 104 | ad.setTitle(result_set.getString("title")); 105 | } 106 | } 107 | catch(SQLException e ) 108 | { 109 | System.out.println(e.getMessage()); 110 | throw e; 111 | } 112 | finally 113 | { 114 | if (adStatement != null) { 115 | adStatement.close(); 116 | }; 117 | if (result_set != null) { 118 | result_set.close(); 119 | } 120 | if (connect != null) { 121 | connect.close(); 122 | } 123 | } 124 | return ad; 125 | } 126 | 127 | 128 | } 129 | --------------------------------------------------------------------------------