RecommendMapper.xml 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.zhentao.mapper.RecommendMapper">
  4. <resultMap id="RecommendUserMap" type="com.zhentao.vo.RecommendUserVO">
  5. <result column="user_id" property="userId"/>
  6. <result column="nickname" property="nickname"/>
  7. <result column="gender" property="gender"/>
  8. <result column="province_id" property="provinceId"/>
  9. <result column="city_id" property="cityId"/>
  10. <result column="area_id" property="areaId"/>
  11. <result column="height" property="height"/>
  12. <result column="weight" property="weight"/>
  13. <result column="education_level" property="educationLevel"/>
  14. <result column="salary_range" property="salaryRange"/>
  15. <result column="hobby" property="hobby"/>
  16. <result column="star" property="star"/>
  17. <result column="animal" property="animal"/>
  18. <result column="school_name" property="schoolName"/>
  19. <result column="job_title" property="jobTitle"/>
  20. <result column="avatar_url" property="avatarUrl"/>
  21. <result column="compatibility_score" property="compatibilityScore"/>
  22. <result column="last_active_at" property="lastActiveAt"/>
  23. </resultMap>
  24. <select id="selectRecommendedUsers" resultMap="RecommendUserMap">
  25. <![CDATA[
  26. SELECT
  27. u.user_id,
  28. u.nickname,
  29. u.gender,
  30. p.province_id,
  31. p.city_id,
  32. p.area_id,
  33. p.height,
  34. p.weight,
  35. p.education_level,
  36. p.salary_range,
  37. p.hobby,
  38. p.star,
  39. p.animal,
  40. p.school_name,
  41. p.job_title,
  42. u.avatar_url,
  43. (
  44. ROUND(
  45. (
  46. 1.0 * (COALESCE(p.authenticity_score, 0) / 100.0)
  47. + 0.9 * (
  48. CASE WHEN #{oppoOnly} = 1 AND u.gender <> cur.cu_gender THEN 1
  49. WHEN #{oppoOnly} = 0 THEN 1
  50. ELSE 0 END
  51. )
  52. + 0.8 * (
  53. CASE
  54. WHEN ABS(TIMESTAMPDIFF(YEAR, u.birth_date, cur.cu_birth)) <= 3 THEN 1
  55. WHEN ABS(TIMESTAMPDIFF(YEAR, u.birth_date, cur.cu_birth)) <= 5 THEN 0.5
  56. ELSE 0
  57. END
  58. )
  59. + 0.7 * LEAST(
  60. (
  61. CASE
  62. WHEN p.salary_range >= cur.cu_salary THEN 1
  63. WHEN p.salary_range = cur.cu_salary - 1 THEN 0.5
  64. ELSE 0
  65. END
  66. ),
  67. (
  68. CASE
  69. WHEN cur.cu_salary >= p.salary_range THEN 1
  70. WHEN cur.cu_salary = p.salary_range - 1 THEN 0.5
  71. ELSE 0
  72. END
  73. )
  74. )
  75. + 0.6 * LEAST(
  76. (
  77. CASE
  78. WHEN p.education_level >= cur.cu_edu THEN 1
  79. WHEN p.education_level = cur.cu_edu - 1 THEN 0.5
  80. ELSE 0
  81. END
  82. ),
  83. (
  84. CASE
  85. WHEN cur.cu_edu >= p.education_level THEN 1
  86. WHEN cur.cu_edu = p.education_level - 1 THEN 0.5
  87. ELSE 0
  88. END
  89. )
  90. )
  91. + 0.5 * (
  92. CASE
  93. WHEN p.height IS NOT NULL AND cur.cu_height IS NOT NULL THEN
  94. CASE
  95. WHEN ABS(p.height - cur.cu_height) <= 5 THEN 1
  96. WHEN ABS(p.height - cur.cu_height) <= 10 THEN 0.5
  97. ELSE 0
  98. END
  99. ELSE 0
  100. END
  101. )
  102. + 0.4 * (
  103. CASE WHEN JSON_OVERLAPS(p.hobby, cur.cu_hobby) THEN 1 ELSE 0 END
  104. )
  105. + 0.3 * (
  106. CASE WHEN p.city_id = cur.cu_city THEN 1
  107. WHEN p.province_id = cur.cu_province THEN 0.5 ELSE 0 END
  108. )
  109. + 0.2 * (
  110. CASE
  111. WHEN p.star IS NOT NULL AND cur.cu_star IS NOT NULL THEN
  112. CASE
  113. WHEN p.star = cur.cu_star THEN 1
  114. WHEN (
  115. (CASE
  116. WHEN p.star IN ('白羊座','狮子座','射手座') THEN 1
  117. WHEN p.star IN ('金牛座','处女座','摩羯座') THEN 2
  118. WHEN p.star IN ('双子座','天秤座','水瓶座') THEN 3
  119. WHEN p.star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  120. ELSE 0
  121. END)
  122. =
  123. (CASE
  124. WHEN cur.cu_star IN ('白羊座','狮子座','射手座') THEN 1
  125. WHEN cur.cu_star IN ('金牛座','处女座','摩羯座') THEN 2
  126. WHEN cur.cu_star IN ('双子座','天秤座','水瓶座') THEN 3
  127. WHEN cur.cu_star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  128. ELSE 0
  129. END)
  130. ) THEN 0.75
  131. WHEN (
  132. (
  133. (CASE
  134. WHEN p.star IN ('白羊座','狮子座','射手座') THEN 1
  135. WHEN p.star IN ('金牛座','处女座','摩羯座') THEN 2
  136. WHEN p.star IN ('双子座','天秤座','水瓶座') THEN 3
  137. WHEN p.star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  138. ELSE 0
  139. END) = 1
  140. AND
  141. (CASE
  142. WHEN cur.cu_star IN ('白羊座','狮子座','射手座') THEN 1
  143. WHEN cur.cu_star IN ('金牛座','处女座','摩羯座') THEN 2
  144. WHEN cur.cu_star IN ('双子座','天秤座','水瓶座') THEN 3
  145. WHEN cur.cu_star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  146. ELSE 0
  147. END) = 3
  148. ) OR (
  149. (CASE
  150. WHEN p.star IN ('白羊座','狮子座','射手座') THEN 1
  151. WHEN p.star IN ('金牛座','处女座','摩羯座') THEN 2
  152. WHEN p.star IN ('双子座','天秤座','水瓶座') THEN 3
  153. WHEN p.star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  154. ELSE 0
  155. END) = 3
  156. AND
  157. (CASE
  158. WHEN cur.cu_star IN ('白羊座','狮子座','射手座') THEN 1
  159. WHEN cur.cu_star IN ('金牛座','处女座','摩羯座') THEN 2
  160. WHEN cur.cu_star IN ('双子座','天秤座','水瓶座') THEN 3
  161. WHEN cur.cu_star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  162. ELSE 0
  163. END) = 1
  164. ) OR (
  165. (CASE
  166. WHEN p.star IN ('白羊座','狮子座','射手座') THEN 1
  167. WHEN p.star IN ('金牛座','处女座','摩羯座') THEN 2
  168. WHEN p.star IN ('双子座','天秤座','水瓶座') THEN 3
  169. WHEN p.star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  170. ELSE 0
  171. END) = 2
  172. AND
  173. (CASE
  174. WHEN cur.cu_star IN ('白羊座','狮子座','射手座') THEN 1
  175. WHEN cur.cu_star IN ('金牛座','处女座','摩羯座') THEN 2
  176. WHEN cur.cu_star IN ('双子座','天秤座','水瓶座') THEN 3
  177. WHEN cur.cu_star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  178. ELSE 0
  179. END) = 4
  180. ) OR (
  181. (CASE
  182. WHEN p.star IN ('白羊座','狮子座','射手座') THEN 1
  183. WHEN p.star IN ('金牛座','处女座','摩羯座') THEN 2
  184. WHEN p.star IN ('双子座','天秤座','水瓶座') THEN 3
  185. WHEN p.star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  186. ELSE 0
  187. END) = 4
  188. AND
  189. (CASE
  190. WHEN cur.cu_star IN ('白羊座','狮子座','射手座') THEN 1
  191. WHEN cur.cu_star IN ('金牛座','处女座','摩羯座') THEN 2
  192. WHEN cur.cu_star IN ('双子座','天秤座','水瓶座') THEN 3
  193. WHEN cur.cu_star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  194. ELSE 0
  195. END) = 2
  196. )
  197. ) THEN 0.5
  198. ELSE 0
  199. END
  200. ELSE 0
  201. END
  202. )
  203. + 0.1 * (
  204. CASE
  205. WHEN p.animal IS NOT NULL AND cur.cu_animal IS NOT NULL THEN
  206. CASE
  207. WHEN p.animal = cur.cu_animal THEN 1
  208. WHEN (
  209. (CASE
  210. WHEN p.animal IN ('猴','鼠','龙') THEN 1
  211. WHEN p.animal IN ('猪','兔','羊') THEN 2
  212. WHEN p.animal IN ('虎','马','狗') THEN 3
  213. WHEN p.animal IN ('蛇','鸡','牛') THEN 4
  214. ELSE 0
  215. END)
  216. =
  217. (CASE
  218. WHEN cur.cu_animal IN ('猴','鼠','龙') THEN 1
  219. WHEN cur.cu_animal IN ('猪','兔','羊') THEN 2
  220. WHEN cur.cu_animal IN ('虎','马','狗') THEN 3
  221. WHEN cur.cu_animal IN ('蛇','鸡','牛') THEN 4
  222. ELSE 0
  223. END)
  224. ) THEN 0.75
  225. WHEN (
  226. (p.animal = '鼠' AND cur.cu_animal = '牛') OR (p.animal = '牛' AND cur.cu_animal = '鼠') OR
  227. (p.animal = '虎' AND cur.cu_animal = '猪') OR (p.animal = '猪' AND cur.cu_animal = '虎') OR
  228. (p.animal = '兔' AND cur.cu_animal = '狗') OR (p.animal = '狗' AND cur.cu_animal = '兔') OR
  229. (p.animal = '龙' AND cur.cu_animal = '鸡') OR (p.animal = '鸡' AND cur.cu_animal = '龙') OR
  230. (p.animal = '蛇' AND cur.cu_animal = '猴') OR (p.animal = '猴' AND cur.cu_animal = '蛇') OR
  231. (p.animal = '马' AND cur.cu_animal = '羊') OR (p.animal = '羊' AND cur.cu_animal = '马')
  232. ) THEN 0.75
  233. ELSE 0
  234. END
  235. ELSE 0
  236. END
  237. )
  238. + 0.05 * (
  239. CASE WHEN p.school_name IS NOT NULL AND cur.cu_school IS NOT NULL AND p.school_name = cur.cu_school THEN 1 ELSE 0 END
  240. )
  241. + 0.05 * (
  242. CASE
  243. WHEN p.job_title IS NOT NULL AND cur.cu_job_title IS NOT NULL THEN
  244. CASE
  245. WHEN p.job_title = cur.cu_job_title THEN 1
  246. WHEN p.job_title LIKE CONCAT('%', cur.cu_job_title, '%') OR cur.cu_job_title LIKE CONCAT('%', p.job_title, '%') THEN 0.5
  247. ELSE 0
  248. END
  249. ELSE 0
  250. END
  251. )
  252. + 0.05 * (
  253. CASE
  254. WHEN p.weight IS NOT NULL AND cur.cu_weight IS NOT NULL THEN
  255. CASE
  256. WHEN ABS(p.weight - cur.cu_weight) <= 5 THEN 1
  257. WHEN ABS(p.weight - cur.cu_weight) <= 10 THEN 0.5
  258. ELSE 0
  259. END
  260. ELSE 0
  261. END
  262. )
  263. + 0.05 * (
  264. CASE
  265. WHEN u.last_active_at >= NOW() - INTERVAL 7 DAY THEN 1
  266. WHEN u.last_active_at >= NOW() - INTERVAL 30 DAY THEN 0.4
  267. ELSE 0
  268. END
  269. )
  270. ) / 5.7 * 100
  271. , 2)
  272. ) AS compatibility_score,
  273. u.last_active_at
  274. FROM users u
  275. JOIN user_profile p ON p.user_id = u.user_id
  276. CROSS JOIN (
  277. SELECT
  278. u.user_id AS cu_id,
  279. u.gender AS cu_gender,
  280. u.birth_date AS cu_birth,
  281. up.city_id AS cu_city,
  282. up.province_id AS cu_province,
  283. up.height AS cu_height,
  284. up.weight AS cu_weight,
  285. up.education_level AS cu_edu,
  286. up.salary_range AS cu_salary,
  287. up.hobby AS cu_hobby,
  288. up.star AS cu_star
  289. ,up.animal AS cu_animal
  290. ,up.school_name AS cu_school
  291. ,up.job_title AS cu_job_title
  292. FROM users u
  293. JOIN user_profile up ON up.user_id = u.user_id
  294. WHERE u.user_id = #{userId}
  295. ) cur
  296. WHERE u.user_id <> cur.cu_id
  297. AND u.status = 1
  298. AND (#{oppoOnly} = 0 OR u.gender <> cur.cu_gender)
  299. ORDER BY compatibility_score DESC, u.last_active_at DESC
  300. LIMIT #{limit}
  301. ]]>
  302. </select>
  303. <select id="selectByRules" resultMap="RecommendUserMap">
  304. SELECT
  305. u.user_id,
  306. u.nickname,
  307. u.gender,
  308. u.avatar_url,
  309. p.province_id,
  310. p.city_id,
  311. p.area_id,
  312. p.height,
  313. p.education_level,
  314. p.salary_range,
  315. p.star,
  316. p.animal,
  317. p.hobby,
  318. (
  319. ROUND(
  320. (
  321. 1.0 * (COALESCE(p.authenticity_score, 0) / 100.0)
  322. + 0.9 * (
  323. CASE WHEN u.gender &lt;&gt; cur.cu_gender THEN 1 ELSE 0.2 END
  324. ) /* 不同性别权重更高,相同性别给予较低分 */
  325. + 0.8 * (
  326. CASE
  327. WHEN ABS(TIMESTAMPDIFF(YEAR, u.birth_date, cur.cu_birth)) &lt;= 3 THEN 1
  328. WHEN ABS(TIMESTAMPDIFF(YEAR, u.birth_date, cur.cu_birth)) &lt;= 5 THEN 0.5
  329. ELSE 0
  330. END
  331. )
  332. + 0.7 * LEAST(
  333. (
  334. CASE
  335. WHEN p.salary_range &gt;= cur.cu_salary THEN 1
  336. WHEN p.salary_range = cur.cu_salary - 1 THEN 0.5
  337. ELSE 0
  338. END
  339. ),
  340. (
  341. CASE
  342. WHEN cur.cu_salary &gt;= p.salary_range THEN 1
  343. WHEN cur.cu_salary = p.salary_range - 1 THEN 0.5
  344. ELSE 0
  345. END
  346. )
  347. )
  348. + 0.6 * LEAST(
  349. (
  350. CASE
  351. WHEN p.education_level &gt;= cur.cu_edu THEN 1
  352. WHEN p.education_level = cur.cu_edu - 1 THEN 0.5
  353. ELSE 0
  354. END
  355. ),
  356. (
  357. CASE
  358. WHEN cur.cu_edu &gt;= p.education_level THEN 1
  359. WHEN cur.cu_edu = p.education_level - 1 THEN 0.5
  360. ELSE 0
  361. END
  362. )
  363. )
  364. + 0.5 * (
  365. CASE
  366. WHEN p.height IS NOT NULL AND cur.cu_height IS NOT NULL THEN
  367. CASE
  368. WHEN ABS(p.height - cur.cu_height) &lt;= 5 THEN 1
  369. WHEN ABS(p.height - cur.cu_height) &lt;= 10 THEN 0.5
  370. ELSE 0
  371. END
  372. ELSE 0
  373. END
  374. )
  375. + 0.4 * (
  376. CASE WHEN JSON_OVERLAPS(p.hobby, cur.cu_hobby) THEN 1 ELSE 0 END
  377. )
  378. + 0.3 * (
  379. CASE WHEN p.city_id = cur.cu_city THEN 1
  380. WHEN p.province_id = cur.cu_province THEN 0.5 ELSE 0 END
  381. )
  382. + 0.2 * (
  383. CASE
  384. WHEN p.star IS NOT NULL AND cur.cu_star IS NOT NULL THEN
  385. CASE
  386. WHEN p.star = cur.cu_star THEN 1
  387. WHEN (
  388. (CASE
  389. WHEN p.star IN ('白羊座','狮子座','射手座') THEN 1
  390. WHEN p.star IN ('金牛座','处女座','摩羯座') THEN 2
  391. WHEN p.star IN ('双子座','天秤座','水瓶座') THEN 3
  392. WHEN p.star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  393. ELSE 0
  394. END)
  395. =
  396. (CASE
  397. WHEN cur.cu_star IN ('白羊座','狮子座','射手座') THEN 1
  398. WHEN cur.cu_star IN ('金牛座','处女座','摩羯座') THEN 2
  399. WHEN cur.cu_star IN ('双子座','天秤座','水瓶座') THEN 3
  400. WHEN cur.cu_star IN ('巨蟹座','天蝎座','双鱼座') THEN 4
  401. ELSE 0
  402. END)
  403. ) THEN 0.75
  404. ELSE 0
  405. END
  406. ELSE 0
  407. END
  408. )
  409. + 0.1 * (
  410. CASE
  411. WHEN p.animal IS NOT NULL AND cur.cu_animal IS NOT NULL THEN
  412. CASE WHEN p.animal = cur.cu_animal THEN 1 ELSE 0 END
  413. ELSE 0
  414. END
  415. )
  416. + 0.05 * (
  417. CASE WHEN p.school_name IS NOT NULL AND cur.cu_school IS NOT NULL AND p.school_name = cur.cu_school THEN 1 ELSE 0 END
  418. )
  419. + 0.05 * (
  420. CASE
  421. WHEN p.job_title IS NOT NULL AND cur.cu_job_title IS NOT NULL THEN
  422. CASE
  423. WHEN p.job_title = cur.cu_job_title THEN 1
  424. WHEN p.job_title LIKE CONCAT('%', cur.cu_job_title, '%') OR cur.cu_job_title LIKE CONCAT('%', p.job_title, '%') THEN 0.5
  425. ELSE 0
  426. END
  427. ELSE 0
  428. END
  429. )
  430. + 0.05 * (
  431. CASE
  432. WHEN p.weight IS NOT NULL AND cur.cu_weight IS NOT NULL THEN
  433. CASE
  434. WHEN ABS(p.weight - cur.cu_weight) &lt;= 5 THEN 1
  435. WHEN ABS(p.weight - cur.cu_weight) &lt;= 10 THEN 0.5
  436. ELSE 0
  437. END
  438. ELSE 0
  439. END
  440. )
  441. + 0.05 * (
  442. CASE
  443. WHEN u.last_active_at &gt;= NOW() - INTERVAL 7 DAY THEN 1
  444. WHEN u.last_active_at &gt;= NOW() - INTERVAL 30 DAY THEN 0.4
  445. ELSE 0
  446. END
  447. )
  448. ) / 5.7 * 100
  449. , 2)
  450. ) AS compatibility_score
  451. FROM users u
  452. JOIN user_profile p ON p.user_id = u.user_id
  453. CROSS JOIN (
  454. SELECT
  455. u.user_id AS cu_id,
  456. u.gender AS cu_gender,
  457. u.birth_date AS cu_birth,
  458. up.city_id AS cu_city,
  459. up.province_id AS cu_province,
  460. up.height AS cu_height,
  461. up.weight AS cu_weight,
  462. up.education_level AS cu_edu,
  463. up.salary_range AS cu_salary,
  464. up.hobby AS cu_hobby,
  465. up.star AS cu_star,
  466. up.animal AS cu_animal,
  467. up.school_name AS cu_school,
  468. up.job_title AS cu_job_title
  469. FROM users u
  470. LEFT JOIN user_profile up ON up.user_id = u.user_id
  471. WHERE u.user_id = #{q.userId}
  472. ) cur
  473. <where>
  474. u.status = 1
  475. <if test="q.userId != null">AND u.user_id &lt;&gt; #{q.userId}</if>
  476. AND (
  477. (#{q.gender} IS NOT NULL AND u.gender = #{q.gender})
  478. OR (#{q.gender} IS NULL AND (cur.cu_gender IS NULL OR u.gender &lt;&gt; cur.cu_gender))
  479. )
  480. <if test="q.provinceId != null">AND p.province_id = #{q.provinceId}</if>
  481. <if test="q.cityId != null">AND p.city_id = #{q.cityId}</if>
  482. <if test="q.areaId != null">AND p.area_id = #{q.areaId}</if>
  483. <if test="q.heightMin != null">AND p.height &gt;= #{q.heightMin}</if>
  484. <if test="q.heightMax != null">AND p.height &lt;= #{q.heightMax}</if>
  485. <if test="q.educationMin != null">AND p.education_level &gt;= #{q.educationMin}</if>
  486. <if test="q.salaryMin != null">AND p.salary_range &gt;= #{q.salaryMin}</if>
  487. <if test="q.star != null">AND p.star = #{q.star}</if>
  488. <if test="q.animal != null">AND p.animal = #{q.animal}</if>
  489. <if test="hobbyJson != null">AND JSON_OVERLAPS(p.hobby, #{hobbyJson})</if>
  490. <if test="birthMin != null">AND u.birth_date &gt;= #{birthMin}</if>
  491. <if test="birthMax != null">AND u.birth_date &lt;= #{birthMax}</if>
  492. <if test="excludeIds != null and excludeIds.size() &gt; 0">
  493. AND u.user_id NOT IN
  494. <foreach collection="excludeIds" item="id" open="(" separator="," close=")">#{id}</foreach>
  495. </if>
  496. </where>
  497. ORDER BY compatibility_score DESC, u.last_active_at DESC
  498. LIMIT #{limit} OFFSET #{offset}
  499. </select>
  500. <select id="selectAllProvinces" resultType="com.zhentao.pojo.Province">
  501. SELECT id, name FROM province ORDER BY id
  502. </select>
  503. <select id="selectAllCities" resultType="com.zhentao.pojo.City">
  504. SELECT id, name, province_id FROM city ORDER BY id
  505. </select>
  506. <select id="selectCitiesByProvince" resultType="com.zhentao.pojo.City">
  507. SELECT id, name, province_id FROM city WHERE province_id = #{provinceId} ORDER BY id
  508. </select>
  509. <select id="selectAreasByCity" resultType="com.zhentao.pojo.Area">
  510. SELECT id, name, city_id FROM area WHERE city_id = #{cityId} ORDER BY id
  511. </select>
  512. </mapper>