0, '小学' => 1, '初中' => 2, '初中及初中以下' => 2, '中专' => 4, '高中' => 4, '高中/中专' => 4, '大专' => 5, '专科' => 5, '本科' => 6, '硕士' => 7, '硕士以上' => 7,'博士' => 8, ]; public static $static_ai_users; public static $static_ai_reviews; public static $static_ai_browses; public static $static_city_gps; public static $static_other_city; public static $static_city_pin_yin; public static $static_preview; public static $static_browse; public static $static_black_list; public static $static_user_except; /** * 产生毫秒级的时间 * @return float */ private function micro_time_float(): float { list($microsecond, $second) = explode(" ", microtime()); return ((float)$microsecond + (float)$second); } /** * 用户初始化文件 * @param null $new_user_id_list * @return bool */ public function initUser(){ $system_black_ids = SBlacklist::whereNull('deleted_at')->pluck('user_id'); $profiles = Profile::with('member', 'match', 'blacklists', 'requests', 'friends', 'dislikes', 'previews', 'browses') ->withCount('photos')->whereNotNull('belief')->whereNotNull('sex') ->whereNotNull('province')->whereNotNull('city')/*->whereNotNull('state')*/ ->whereNotIn('user_id', $system_black_ids->toArray()) ->wherehas('member', function ($sql) { $sql->where('hidden_profile', 'NONE')->where('sex', '>', 0); });//->orderByDesc('info_complete_score'); //Log::notice('[initUser] load all auth user tables from mysql, on:' . (self::micro_time_float() - $start1)); $send_female_ids = []; $send_male_ids = []; $receive_user_list = []; $receive_female_ids = []; $receive_male_ids = []; $worker_female_ids = []; $worker_male_ids = []; $total_user = $profiles->count(); $current_user = 0; $profiles->chunk(1000, function ($profiles) use ( &$send_female_ids, &$send_male_ids, &$receive_user_list, $total_user, &$current_user, $system_black_ids, &$receive_female_ids, &$receive_male_ids, &$worker_female_ids, &$worker_male_ids ) { $i = 0; foreach ($profiles as $profile) { $i++; $id = $profile->user_id; $member = $profile->member; if (empty($member->sex) || $member->sex < 1 || $profile->sex != $member->sex) { error_log('[initUser] 出错 ID = ' . $id . ' 性别异常,跳过.'); Log::warning('[initUser] 出错 ID = ' . $id . ' 性别异常,跳过.'); continue; } /** if (empty($member->belief) || $profile->belief != $member->belief) { error_log('[initUser] 出错 ID = ' . $id . ' 信仰异常,跳过.'); Log::warning('[initUser] 出错 ID = ' . $id . ' 信仰异常,跳过.'); continue; } * */ $user = []; $user['id'] = $id; //profile $user['birthday'] = $profile->birthday; $user['belief'] = $profile->belief; $user['province'] = $profile->province; $user['city'] = $profile->city; $user['state'] = $profile->state; $user['weight'] = $profile->weight; $user['stature'] = $profile->stature; $user['stature'] = $profile->stature; $user['resident_province'] = $profile->resident_province; $user['resident_city'] = $profile->resident_city; $user['degree'] = $profile->degree; //like setting $user['max_age'] = $profile->max_age; $user['min_age'] = $profile->min_age; $user['min_height'] = $profile->min_height; $user['max_height'] = $profile->max_height; $user['city_claim'] = $profile->city_claim; $user['city_list_claim'] = $profile->city_list_claim; $user['hometown_claim'] = $profile->hometown_claim; $user['approve_claim'] = $profile->approve_claim; $user['show_score'] = strlen($profile->introduction) + strlen($profile->ideal_mate); $user['photos_count'] = $profile->photos_count; if (isset($profile->match) && $profile->match->score > 70) { $user['is_match'] = 1; } else { $user['is_match'] = 0; } if (isset($member->sex)) { $user['sex'] = $member->sex; } else { error_log('Exception sex on user_id=' . $id); continue; } $user['face_score'] = $member->face_score; $user['photo'] = $member->photo; $user['location_longitude'] = $member->location_longitude; $user['location_latitude'] = $member->location_latitude; $user['rank_id'] = $member->rank_id; $user['type'] = $member->type; $user['name'] = $member->name; $user['is_approved'] = $member->is_approved; $user['approve_date'] = $member->approve_date; $user['is_photo_audited'] = $member->is_photo_audited; $user['is_real_approved'] = $member->is_real_approved; $user['is_educate_approved'] = $member->is_educate_approved; $negative_score = $member->negative_score; //好友请求不处理,加负面分 $friend_request = Request::where('user_id', $id)->orderBy('id', 'desc')->limit(15)->get(); if (!empty($friend_request)) { $index = 0; foreach ($friend_request as $request) { if ($request->status == 1 || $request->status == -1) { break; } else { $index += 1; } } if ($index > 0 && $index < 5) { $negative_score += 10; } if ($index > 5 && $index < 10) { $negative_score += 20; } if ($index > 10) { $negative_score += 50; } } if ($negative_score > 200) { $negative_score = 200; } $user['negative_score'] = $negative_score; $user['info_complete_score'] = $member->info_complete_score; $user['liveness'] = $member->liveness; $user['last_visit'] = $member->last_visit; $user['deleted_at'] = $member->deleted_at; $user['hidden_profile'] = $member->hidden_profile; $user['mobile'] = $member->mobile; $user['id'] = $member->id; $user['init_time'] = date('Y-m-d H:i:s'); $time = mt_rand(60*60*12,60*60*24); Redis::setex('ai:user:' . $id,$time, json_encode($user)); self::$static_ai_users[$id] = $user; $receive_user_list[] = $id; //接收人 if ($profile->previews->count()) { $preview_ids = []; foreach ($profile->previews as $item) { if (!in_array($item->user_id, $preview_ids)) { //重复查看详情,跳过 $preview_ids[] = $item->user_id; } } self::$static_preview[$id] = $preview_ids; Redis::set('ai:preview:' . $id, json_encode($preview_ids)); //查看详情信息入redis } if ($profile->browses->count()) { $browse_ids = []; foreach ($profile->browses as $item) { if (!in_array($item->other_user_id, $browse_ids)) { $browse_ids[] = $item->other_user_id; } } Redis::set('ai:browse:' . $id, json_encode($browse_ids)); self::$static_browse[$id] = $browse_ids; } $except_ids = []; //异常idList if ($profile->blacklists->count()) { //黑名单加到异常列表 foreach ($profile->blacklists as $item) { if ($item->deleted_at == null) { $except_ids[] = $item->other_user_id; } } } if ($profile->friends->count()) { //好友加到异常列表 foreach ($profile->friends as $item) { $except_ids[] = $item->user_id; } } if ($profile->requests->count()) { //好友请求加异常列表 foreach ($profile->requests as $item) { $except_ids[] = $item->user_linking_id; } } if ($profile->dislikes->count() > 0) { //不喜欢加异常列表 foreach ($profile->dislikes as $item) { $except_ids[] = $item->type_id; } } if (!empty($except_ids)) { //异常列表保存 Redis::set('ai:except:' . $id, json_encode(array_values(array_unique($except_ids)))); self::$static_user_except[$id] = $except_ids; } if ($member->type == 'single') { //单身 if ($member->sex == 1) { if (!in_array($id, self::WORKER_USER_ID_LIST)) { //不在工作人员列表且实名 if ($member->is_real_approved || ($member->is_approved)) { if (!empty($member->face_score) && $member->face_score > 40.0) { //颜值低于40不推荐 $send_male_ids[] = $id; } } } if (!in_array($id, $receive_male_ids)) { $receive_male_ids[] = $id; } } else if ($member->sex == 2) { if (!in_array($id, self::WORKER_USER_ID_LIST)) { //不在工作人员列表且实名 if ($member->is_real_approved || ($member->is_approved)) { if (!empty($member->face_score) && $member->face_score > 40.0) { //颜值低于40不推荐 $send_female_ids[] = $id; } } } if (!in_array($id, $receive_female_ids)) { $receive_female_ids[] = $id; } } } else { //marriage和loveing if ($member->sex == 1) { $worker_male_ids[] = $id; if (!in_array($id, $receive_male_ids)) { $receive_male_ids[] = $id; } } else if ($member->sex == 2) { $worker_female_ids[] = $id; if (!in_array($id, $receive_female_ids)) { $receive_female_ids[] = $id; } } } } }); Redis::set('ai:send:female:ids', json_encode(array_unique($send_female_ids))); Redis::set('ai:send:male:ids', json_encode(array_unique($send_male_ids))); Redis::set('ai:recv:ids', json_encode(array_unique($receive_user_list))); Redis::set('ai:recv:female:ids', json_encode(array_unique($receive_female_ids))); Redis::set('ai:recv:male:ids', json_encode(array_unique($receive_male_ids))); Redis::set('ai:recv:female_marriage:ids', json_encode(array_unique($worker_female_ids))); //工作人员 Redis::set('ai:recv:male_marriage:ids', json_encode(array_unique($worker_male_ids))); //工作人员 //Log::notice('[initUser] save user, on:' . (self::micro_time_float() - $start) . ',total_user:' . $total_user . ',current: ' . $current_user); return true; } /** * 用户推荐主处理程序 * @param $receive_user_list * @param $send_user_list * @return array|\Illuminate\Support\Collection|null */ public function initRecommendScore($receive_user_list, $send_user_list,$recode_number) { try { $items = null; // $send_female_ids = json_decode(Redis::get('ai:send:female:ids'), true)?:[]; // Log::info("send_female_ids_count: :".count($send_female_ids)); // $send_male_ids = json_decode(Redis::get('ai:send:male:ids'), true)?:[]; // Log::info("send_male_ids_count: :".count($send_male_ids)); $redis = Redis::connection('big_data'); $send_female_ids = json_decode($redis->get('ai:send:female:ids'), true)?:[]; Log::info("send_female_ids_count: :".count($send_female_ids)); $send_male_ids = json_decode($redis->get('ai:send:male:ids'), true)?:[]; Log::info("send_male_ids_count: :".count($send_male_ids)); $index = 0; if ($send_user_list) { $inside = 1; } else { $inside = 0; } foreach ($receive_user_list as $receive_id) { $index++; $receive_user = $this->getUser($receive_id,'receive_user'); if (empty($receive_user)) { continue; } if (empty($receive_user->type)) { continue; } if ($receive_user->type == 'single') { //单身 if (!$send_user_list) { if ($receive_user->sex == 1) { $send_user_list = $send_female_ids; } else { $send_user_list = $send_male_ids; } } } else { //marriage和loveing都是介绍人 $send_user_list = array_merge($send_male_ids, $send_female_ids); } if(empty($send_user_list)){ $this->initUser(); } $exceptList = Redis::get('ai:except:' . $receive_id); //读取该用户ID的异常列表 if (!empty($exceptList)) { //从推荐的用户列表中排除在异常更表中的ID $exceptList = json_decode($exceptList, true); if(!empty($exceptList)){ $send_user_list = array_diff($send_user_list, $exceptList); } } //$start1 = self::micro_time_float(); $items = collect(); $is_recmd_num = 0; $is_valid_num = 0; foreach ($send_user_list as $send_user) { $result = $this->calculateUserScore($receive_id, $send_user); if ($result && isset($result['data'])) { $recmd = $result['data']; $recmd->match_time = date('Y-m-d H:i:s'); $recmd->send_user = $this->getUser($send_user,'sender_user'); $items->push($recmd); $is_recmd_num++; if ($recmd->score > 150) { //如返回的score > 150,有效人数加1 $is_valid_num++; } //} } else { continue; } } //$items->receive_user = $receive_user; //$recmd_status->push(['id' => $receive_id, 'is_recmd_num' => $is_recmd_num, 'is_valid_num' => $is_valid_num]); //推荐状态 $items = $items->sortByDesc(function ($item) { //按分数排序 return $item->is_recommend * 100 + $item->score; })->take($recode_number); if (empty($items->toArray())) { continue; } else { $items = array_values($items->toArray()); if ($inside) { //Redis::setex('ai:recmd:score:inside:' . $receive_id, 60 * 60 * 24, json_encode($items)); } else { Redis::setex('ai:recmd:score:all:' . $receive_id, 60 * 60 * 24, json_encode($items)); } } } return $items; }catch (\Exception $e){ throw new \Exception($e); } } /** * 当用户不在ai:user中时,检查不在原因 * @param $userId * @return array|bool * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function checkUser($userId,$user_type) { try { $user = Profile::leftJoin('users', 'profile_courtships.user_id', '=', 'users.id') ->select( 'profile_courtships.birthday', 'profile_courtships.belief', 'profile_courtships.province', 'profile_courtships.city', 'profile_courtships.state', 'profile_courtships.weight', 'profile_courtships.stature', 'profile_courtships.resident_province', 'profile_courtships.resident_city', 'profile_courtships.degree', 'profile_courtships.max_age', 'profile_courtships.min_age', 'profile_courtships.min_height', 'profile_courtships.max_height', 'profile_courtships.city_claim', 'profile_courtships.city_list_claim', 'profile_courtships.hometown_claim', 'profile_courtships.approve_claim', 'profile_courtships.belief', 'users.sex','profile_courtships.province','profile_courtships.city', 'users.face_score', 'users.photo','users.location_longitude', 'users.location_latitude','users.rank_id', 'users.type', 'users.is_approved','users.approve_date', 'users.is_photo_audited','users.is_real_approved', 'users.is_educate_approved', 'users.negative_score','users.info_complete_score', 'users.hidden_profile', 'users.mobile','users.id','users.name','users.last_visit') ->where('user_id', $userId)->first(); if ($user) { if($user_type == 'sender_user'){ if ($user->hidden_profile != 'NONE') { return ['status' => 'fail', 'data' => [], 'error' => '用户设置为隐藏']; } } if (empty($user->sex)) { return ['status' => 'fail', 'data' => [], 'error' => '用户未设置性别']; } elseif (empty($user->province)) { return ['status' => 'fail', 'data' => [], 'error' => '用户未设置省份']; //} elseif (empty($user->city)) { // return ['status' => 'fail', 'data' => [], 'error' => '用户未设置城市']; } elseif (empty($user->state)) { return ['status' => 'fail', 'data' => [], 'error' => '用户未设置单身状态']; } $user['init_time'] = date('Y-m-d H:i:s'); $time = mt_rand(60*60*12,60*60*24); Redis::setex('ai:user:' . $user->id,$time,json_encode($user)); self::$static_ai_users[$user->id] = $user; return $user; } else { return ['status' => 'fail', 'data' => [], 'error' => '没有这个用户']; } } catch (Exception $e) { return false; } } /** * 字符串截取指定长度 * @param $text * @param $length * @param string $replace * @param string $encoding * @return string */ public function substring_format($text, $length, $replace = '......', $encoding = 'UTF-8') { if ($text && mb_strlen($text, $encoding) > $length) { return mb_substr($text, 0, $length, $encoding) . $replace; } return $text; } /** * 计算两个用户的分值 * 将send_user_id 推给 user_id * @param $user_id * @param $send_user_id * @param bool $is_full * @return bool|mixed * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateUserScore($user_id, $send_user_id) { //获取用户信息 $user = $this->getUser($user_id,'receive_user'); if (empty($user)) { return ['code' => 1, 'msg' => "用户【" . $user_id . "】没有缓存数据,"]; } $send_user = $this->getUser($send_user_id,'sender_user'); if (empty($send_user)) { return ['code' => 1, 'msg' => "用户【" . $send_user_id . "】没有缓存数据,"]; } /** if (empty($send_user->photo)) { return ['code' => 1, 'msg' => "用户【" . $send_user_id . "】没有头像,"]; } **/ if ($user->type == 'single' && $user->type == $send_user->type && $user->sex == $send_user->sex) { return ['code' => 1, 'msg' => ' send_user_id - user_id :' . $send_user_id . '-' . $user_id . ',单身同性别,']; } /** //颜值低于40的用户不推荐 if ($send_user->face_score == 0.00 || $send_user->face_score < 30.00) { return ['code' => 1, 'msg' => ' send_user_id ' . $send_user_id . ' 颜值低于40,不能推荐,']; } **/ /** 检测单身状态 */ /** $type_res = $this->checkType($user, $send_user); if (!empty($type_res['code'])) return $type_res; **/ $msg = ''; // 计算基础分数 $base_res = $this->calculateBaseScore($user, $send_user); if ($base_res['code']) return $base_res; $base_score = $base_res['data']; $msg .= $base_res['msg']; /** // 计算动态分 $dynamic_res = $this->calculateDynamicScore($user, $send_user); if ($dynamic_res['code']) return $dynamic_res; $dynamic_score = $dynamic_res['data']; $msg .= $dynamic_res['msg']; **/ // 计算负分 $negative_res = $this->calculateNegativeScore($user, $send_user); if ($negative_res['code']) return $negative_res; $negative_score = $negative_res['data']; $msg .= $negative_res['msg']; // 计算婚姻状况 $marital_status = $this->calculateMaritalStatus($user, $send_user); if ($marital_status['code']) return $marital_status; $marital_status_score = $marital_status['data']; $msg .= $marital_status['msg']; $result = json_decode('{"send_user":' . $send_user_id . ',"receive_user":' . $user_id . '}'); $result->is_recommend = ($base_score == 150) ? 1 : 0; $result->base_score = $base_score; $result->marital_status_score = $marital_status_score; $result->base_score = $base_score; $result->negtive_score = $negative_score; //$result->dync_score = $dynamic_score; $result->score = $base_score + $marital_status_score - $negative_score; //$dynamic_score; return ['code' => 0, 'msg' => $msg, 'data' => $result]; } /** * 获取用户 * @param $id * @return bool|mixed|object * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function getUser($id,$user_type) { try { if (isset(self::$static_ai_users[$id])) { $user = self::$static_ai_users[$id]; if($user){ if(!empty($user['init_time'])) { if (time() - strtotime($user['init_time']) >= 86400) { unset(self::$static_ai_users[$id]); $user = null; } }else{ unset(self::$static_ai_users[$id]); $user = null; } } } else { $user = json_decode(Redis::get('ai:user:' . $id), true); } if (empty($user->id)) { $user = $this->checkUser($id,$user_type); if(!empty($user['status'])){ return false; } Redis::setex('ai:user:' . $id,60*60*24,json_encode($user)); self::$static_ai_users[$id] = $user; return $user; } if (is_array($user)) { $user = (object)$user; } return $user; } catch (Exception $e) { return false; } } /** * 检测单身状态 * @param $user * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function checkType($user, $send_user):array { try { if (empty($user->type) || empty($user->sex) || empty($send_user->sex) || empty($send_user->type)) { return ['code'=>1, 'msg'=>'user_id = ' . $user->id . ', send_user_id =' . $send_user->id . " 有性别信息或者没有用户类型,"]; } //类型不同 if ($user->type != $send_user->type) { //单身 if ($user->type == 'signle') { return ['code'=>1, 'msg'=>'receive_user_id = ' . $user->id . ',send_user_id = ' . $send_user->id . " 介绍人不能匹配给单身,"]; } } else { if ($send_user->type != 'single') { return ['code'=>1, 'msg'=>'receive_user_id = ' . $user->id . ',send_user_id = ' . $send_user->id . " 介绍人之间不能相互匹配,"]; } } return ['code'=>0, 'msg'=>'']; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算receive_user_id=' . $user->id . ',sendUserId=' . $send_user->id . '计算检测单身状态出错,请及时处理!!!,']; } } /** * 婚姻状况检测 * @param $user * @param $send_user * @return array */ public function calculateMaritalStatus($user, $send_user): array { try{ if($user->state && $send_user->state) { if ($user->state == $send_user->state) { $score = 10; } elseif(($user->state == '从未结婚' && $send_user->state == '未婚') || ($send_user->state == '从未结婚' && $user->state == '未婚')) { $score = 10; }else{ $score = 0; } }else{ $score = 10; } return ['code'=>0, 'msg'=>'ok', 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算userId=' . $user->id . ',sendUserId=' . $send_user->id . '计算基础分数出错,请及时处理!!!,']; } } /** * 计算基础分数 * @param $user * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateBaseScore($user, $send_user):array { try { $score = 0; $msg = ''; /** 计算信仰 */ $belief_res = $this->calculateBelief($user, $send_user); if (!empty($belief_res['code'])) return $belief_res; $score += $belief_res['data']; $msg .= $belief_res['msg']; /** 计算年龄 */ $age_res = $this->calculateAge($user, $send_user); if (!empty($age_res['code'])) return $age_res; $score += $age_res['data']; $msg .= $age_res['msg']; /** 计算地域 */ $regional_res = $this->calculateRegional($user, $send_user); if ($regional_res['code']) return $regional_res; $score += $regional_res['data'] * 1.1; $msg .= $regional_res['msg']; /** 计算学历 */ $degree_res = $this->calculateDegreeBaseScore($user, $send_user); if ($degree_res['code']) return $degree_res; $score += $degree_res['data']; $msg .= $degree_res['msg']; /** 计算身高 */ $stature_res = $this->calculateStature($user, $send_user); if ($stature_res['code']) return $stature_res; //$score += $stature_res['data']; $msg .= $stature_res['msg']; /** 计算单身状态 */ $state_res = $this->calculateState($user, $send_user); if ($state_res['code']) return $state_res; $score += $state_res['data']; $msg .= $state_res['msg']; return ['code'=>0, 'msg'=>$msg, 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算userId=' . $user->id . ',sendUserId=' . $send_user->id . '计算基础分数出错,请及时处理!!!,']; } } /** * 计算信仰分数 * @param $user * @param $send_user * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateBelief($user, $send_user):array { try { $score = 10; //同信仰 if ($user->belief == $send_user->belief) { return ['code'=>0, 'msg'=>'','data'=>$score]; } //非同信仰 if (($user->belief == '基督教' && $send_user->belief != '基督教') || ($user->belief == '伊斯兰教' && $send_user->belief != '伊斯兰教') || ($send_user->belief == '基督教' && $user->belief != '基督教') || ($send_user->belief == '伊斯兰教' && $user->belief != '伊斯兰教')) { return ['code'=>0, 'msg'=>'','data'=>0]; } return ['code'=>0, 'msg'=>'','data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=> '计算userId=' . $user->id . ',sendUserId=' . $send_user->id . '计算信仰分数出错,请及时处理!!!,']; } } /** * 计算年龄分数 * @param $user * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateAge($user, $send_user):array { try { $score = 10; $user_age = $this->getAge($user->birthday); $send_user_age = $this->getAge($send_user->birthday); $max_age = $this->getAge($user->max_age); $min_age = $this->getAge($user->min_age); $sub_age = $user_age - $send_user_age; if ($user->type != 'single') { if ($send_user_age>=22 and $send_user_age<=35) { return ['code'=>0, 'msg'=>'', 'data'=>$score]; }else{ return ['code'=>0, 'msg'=>'介绍人推荐的年龄不在22-35之间,', 'data'=>0]; } } //是否要求 if ($min_age && $max_age) { //有要求 if ($send_user_age < $min_age || $send_user_age > $max_age) { return ['code'=>0, 'msg'=>'推荐的年龄不在用户要求范围内'.$min_age.'-'.$max_age.'之间,', 'data'=>0]; } } else { if ($user->sex == 1) { //男 if ($user_age >= 45) { if ($send_user_age < 40) { return ['code'=>0, 'msg'=>'45岁以上男用户推荐的年龄小于40,', 'data'=>0]; } } elseif ($user_age >= 35 && $user_age < 45) { if ($sub_age < -5 || $sub_age > 7) { return ['code'=>0, 'msg'=>'35-45岁男用户推荐的年龄不在小5岁大7岁之间,', 'data'=>0]; } } else { if ($sub_age < -3 || $sub_age > 5) { return ['code'=>0, 'msg'=>'35岁以下男用户推荐的年龄不在小3岁大7岁之间,', 'data'=>0]; } } } else { //女 if ($user_age >= 40) { if ($send_user_age < 40) { return ['code'=>0, 'msg'=>'40岁以上女用户推荐的年龄小于40,', 'data'=>0]; } } elseif ($user_age >= 30 && $user_age < 40) { if ($sub_age < -7 || $sub_age > 5) { return ['code'=>0, 'msg'=>'30-40岁女用户推荐的年龄不在小7岁大5岁之间,', 'data'=>0]; } } else { if ($sub_age < -7 || $sub_age > 3) { return ['code'=>0, 'msg'=>'30岁以下女用户推荐的年龄不在小7岁大3岁之间,', 'data'=>0]; } } } } return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算userId=' . $user->id . ',sendUserId=' . $send_user->id . '年龄分数出错,请及时处理!!!,']; } } /** * 获取年龄 * @param string $birthday 生日 * @return integer 年龄 */ public function getAge($birthday): int { if (empty($birthday)) { return 0; } $age = strtotime($birthday); if ($age === false) { return 0; } list($y1, $m1, $d1) = explode("-", date("Y-m-d", $age)); $now = strtotime("now"); list($y2, $m2, $d2) = explode("-", date("Y-m-d", $now)); $age = $y2 - $y1; if ((int)($m2 . $d2) < (int)($m1 . $d1)) $age -= 1; return $age; } /** * 计算地域分数 * @param $user * @param $send_user * @return array */ public function calculateRegional($user, $send_user):array { try{ $score = 0; if($user->province == $send_user->province){ $score += 5; if($user->city == $send_user->city){ $score += 10; } if($user->resident_province == $send_user->resident_province){ $score += 5; } if($user->resident_city == $send_user->resident_city){ $score += 10; } }else{ if($user->resident_province == $send_user->resident_province){ $score += 5; } if($user->resident_city == $send_user->resident_city){ $score += 10; } } return ['code'=>0, 'msg'=>'', 'data'=>$score]; }catch(\Exception $e){ return false; } } /** *计算某个经纬度的周围某段距离的正方形的四个点 * @param $lng * @param $lat * @param float $distance * @return array 正方形的四个点的经纬度坐标 */ static function returnSquarePoint($lng, $lat, $distance = 0.5) { $EARTH_RADIUS = 6371;//地球半径,平均半径为6371km $dlng = 2 * asin(sin($distance / (2 * $EARTH_RADIUS)) / cos(deg2rad($lat))); $dlng = rad2deg($dlng); $dlat = $distance / $EARTH_RADIUS; $dlat = rad2deg($dlat); return array( 'left_top' => array('lat' => round($lat + $dlat, 2), 'lng' => round($lng - $dlng, 2)), 'right_top' => array('lat' => round($lat + $dlat, 2), 'lng' => round($lng + $dlng, 2)), 'left_bottom' => array('lat' => round($lat - $dlat, 2), 'lng' => round($lng - $dlng, 2)), 'right_bottom' => array('lat' => round($lat - $dlat, 2), 'lng' => round($lng + $dlng, 2)) ); } /** * 计算基础学历分数 * @param $user * @param $send_user * @return arary */ public function calculateDegreeBaseScore($user, $send_user):array { $score = 10; if ($user->type != 'single') { return ['code'=>0, 'msg'=>'', 'data'=>10]; } if (empty($user->degree) || $user->degree == '其它') { $score = 10; } elseif (!empty($user->degree) && !empty($send_user->degree)) { $user_degree_number = self::degree[$send_user->degree]; $send_user_degree_number = self::degree[$user->degree]; if ($user->degree >= 4) { if ($send_user_degree_number > $user_degree_number) { $sub_degree = $send_user_degree_number - $user_degree_number; if($sub_degree > 2){ $score = 0; } } else { $sub_degree = $user_degree_number - $send_user_degree_number; if($sub_degree > 2){ $score = 0; } } } else { if ($send_user_degree_number > $user_degree_number) { $sub_degree = $send_user_degree_number - $user_degree_number; if($sub_degree > 2){ $score = 0; } }elseif ($send_user_degree_number < $user_degree_number) { $sub_degree = $user_degree_number - $send_user_degree_number; if($sub_degree > 2){ $score = 0; } } } } elseif (empty($user->degree) || !empty($send_user->degree)) { $score = 10; } else { return ['code'=>0, 'msg'=>'学历不匹配,', 'data'=>0]; } return ['code'=>0, 'msg'=>'', 'data'=>$score]; } /** * 计算身高分数 * @param $user * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateStature($user, $send_user):array { try { $score = 10; if (isset($user->max_height) && isset($send_user->max_height) && $user->max_height && $user->min_height) { if ($send_user->stature < $user->min_height){ $sub_stature = $user->min_height - $send_user->stature; $score = $score - $sub_stature; if($score <= 5){ $score = 5; } } }elseif($send_user->stature > $user->max_height) { $sub_stature = $send_user->stature - $user->min_height; $score = $score + $sub_stature; if($score >= 12){ $score = 12; } } return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算userId=' . $user->id . ',sendUserId=' . $send_user->id . '身高分数出错,请及时处理!!!,']; } } /** * 计算单身状态分数 * @param $user * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateState($user, $send_user):array { try { $score = 10; return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算userId=' . $user->id . ',sendUserId=' . $send_user->id . '单身状态分数出错,请及时处理!!!,']; } } /** * 计算动态分值 * @param $user * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateDynamicScore($user, $send_user):array { try { $score = 0; //认证分数 $approve_res= $this->calculateApprove($send_user); if ($approve_res['code']) return $approve_res; $score += (int)$approve_res['data']; //地域分数 $regional_res = $this->calculateDynamicRegional($user, $send_user); if ($regional_res['code']) return $regional_res; $score += (int)$regional_res['data']; //活跃度 $liveness_res = $this->calculateLikeness($user, $send_user); if ($liveness_res['code']) return $liveness_res; $score += (int)$liveness_res['data']; //个人介绍完整度分数 $intro_res = $this->calculateIntroScore($send_user); if ($intro_res['code']) return $intro_res; $score += (int)$intro_res['data']; //信息完整度 $complete_info_res = $this->calculateCompleteInfo($send_user); if ($complete_info_res['code']) return $complete_info_res; $score += (int)$complete_info_res['data']; //生活照分数 $live_photo_res = $this->calculateLivePhoto($send_user); if ($live_photo_res['code']) return $live_photo_res; $score += (int)$live_photo_res['data']; //颜值分数 $face_res = $this->calculateFaceScore($user,$send_user); if ($face_res['code']) return $face_res; $score += (int)$face_res['data']; //学历分数 $degree_res = $this->calculateDegreeDynamicScore($user, $send_user); if ($degree_res['code']) return $degree_res; $score += (int)$degree_res['data']; return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=> '计算userId=' . $user->id . ',sendUserId=' . $send_user->id . '动态分值出错,请及时处理!!!,']; } } /** * 计算认证分数 * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateApprove($send_user):array { try { $score = 0; if ($send_user->is_approved) { $score += 1; } if ($send_user->is_real_approved) { $score += 2; } if ($send_user->face_score >= 80) { $score += 2; } if ($send_user->is_educate_approved) { $score += 2; } if ($send_user->rank_id > 0) { $score += 2; } //申请推荐 return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>0, 'msg'=>'计算userId=' . $send_user->id . ',认证分数出错,请及时处理!!!,']; } } /** * 计算动态地域分值 * @param $user * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateDynamicRegional($user, $send_user):array { try { $score = 0; if (($user->province != $send_user->province || empty($send_user->province)) && ($user->resident_province != $send_user->resident_province || empty($send_user->resident_province))) { //非同省同家乡 或者 没有地址信息 $score = 0; } elseif (($user->province != $send_user->province || empty($send_user->province)) && ($user->resident_province == $send_user->resident_province && $user->resident_city != $send_user->resident_city)) { //非同省、同家乡省、非同家乡市 $score += $user->type=="single"?5:5; } elseif (($user->province != $send_user->province || empty($send_user->province)) && $user->resident_city == $send_user->resident_city) { //非同省、同家乡省市 $score += $user->type=="single"?12:12; } elseif (($user->province == $send_user->province && $user->city != $send_user->city) && ($user->resident_province != $send_user->resident_province || empty($send_user->resident_province))) { //同省非同市、非同家乡省 $score += $user->type=="single"?5:5; } elseif (($user->province == $send_user->province && $user->city != $send_user->city) && ($user->resident_province == $send_user->resident_province && $user->resident_city != $send_user->resident_city)) { //同省非同市、同家乡省非同家乡市 $score += $user->type=="single"?10:10; } elseif (($user->province == $send_user->province && $user->city != $send_user->city) && $user->resident_city == $send_user->resident_city) { //同省非同市、同家乡市 $score += $user->type=="single"?17:17; } elseif ($user->city != $send_user->city && $user->resident_province != $send_user->resident_province) { //同市、同家乡省 $score += $user->type=="single"?0:0; } elseif (($user->province == $send_user->province && $user->city != $send_user->city) && $user->resident_city == $send_user->resident_city) { //同省非同市、同家乡市 $score += $user->type=="single"?17:17; } elseif ($user->city == $send_user->city && $user->resident_city == $send_user->resident_city) { //同省非同市、同家乡市 $score += $user->type=="single"?24:24; } return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算userId=' . $user->id . ',sendUserId=' . $send_user->id . '动态地域分值出错,请及时处理!!!,']; } } /** * 计算活跃度分数 * @param $user * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateLikeness($user, $send_user):array { try { $score = 0; //24小时内 $day_visit = strtotime($send_user->last_visit) + 24 * 3600 > time() ? 1 : 0; //本周活跃 $week_visit = strtotime($send_user->last_visit) + 7 * 24 * 3600 > time() ? 1 : 0; //本月活跃 $month_visit = strtotime($send_user->last_visit) + 30 * 24 * 3600 > time() ? 1 : 0; //本年 $year_visit = strtotime($send_user->last_visit) + 365 * 24 * 3600 > time() ? 1 : 0; if ($day_visit) { $score = 10; } elseif ($week_visit) { $score = 5; } elseif ($month_visit) { $score = 2; } elseif ($year_visit) { $score = 1; } return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算userId=' . $user->id . ',sendUserId=' . $send_user->id . '活跃度分数出错,请及时处理!!!,']; } } /** * 计算个人介绍分数 * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateIntroScore($send_user):array { try { $score = isset($send_user->show_score) ? 10: 0; return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算个人介绍分数出错,请及时处理!!!,']; } } /** * 计算新用户分数 * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateNewApprove($send_user) { try { $score = 0; $current_time = time(); $approve_time = strtotime($send_user->approve_date); if ($approve_time + 3 * 24 * 3600 >= $current_time) { $score = 10; } return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>0, 'msg'=> '计算userId=' . $send_user->id . ',新用户分数出错,请及时处理!!!,']; } } /** * 计算信息完整度分数 * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateCompleteInfo($send_user) { try { $info_score = $send_user->info_complete_score; $score = $info_score / 2; return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>0, 'msg'=>'计算userId=' . $send_user->id . ',信息完整度分数出错,请及时处理!!!,']; } } /** * 计算生活照分数 * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateLivePhoto($send_user) { try { $photos_count = isset($send_user->photos_count) ?: 0; switch ($photos_count) { case 0: $score = 0; break; case 1: $score = 4; break; case 2: $score = 6; break; case 3: $score = 8; break; default: $score = 10; break; } return ['code'=>0, 'msg'=>'','data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>"计算userId=' . $send_user->id . ',生活照分数出错,请及时处理!!!,"]; } } /** * 计算颜值分数 * @param $send_user * @return array */ public function calculateFaceScore($user,$send_user) { $score = 10; if($user->face_score && $send_user->face_score){ if($send_user->face_score > $user->face_score ){ $sub_face = $send_user->face_score - $user->face_score; if($sub_face > 10){ $score = 0; }else { $score = $score + $sub_face; if($score > 12){ $score = 12; } } }elseif($send_user->face_score < $user->face_score){ $sub_face = $user->face_score - $send_user->face_score; if($sub_face >= 10){ $score = 0; }else { $score = $score - $sub_face; if($score < 5){ $score = 5; } } } } return ['code'=>0, 'msg'=>'', 'data'=>$score]; } /** * 计算动态学历分数 * @param $user * @param $send_user * @return array */ public function calculateDegreeDynamicScore($user, $send_user) { if (empty($user->degree) || empty($send_user->degree)) { $score = 10; } elseif (!empty($user->degree) && !empty($send_user->degree)) { $user_degree_number = self::degree[$user->degree]; $send_user_degree_number = self::degree[$user->degree]; if ($user_degree_number >= 4) { if ($user_degree_number == $send_user_degree_number) { $score = 10; } elseif ($send_user_degree_number - $user_degree_number > 1) { $score = 5; } elseif ($user_degree_number - $send_user_degree_number > 1 && $send_user_degree_number > 4) { $score = 3; } else { $score = 0; } } elseif ($user_degree_number < 4) { if ($user_degree_number == $send_user_degree_number) { $score = 10; } elseif ($send_user_degree_number - $user_degree_number > 1) { $score = 5; } elseif ($user_degree_number - $send_user_degree_number = 1) { $score = 3; } else { $score = 0; } } else { $score = 0; } } elseif (empty($user->degree) || !empty($send_user->degree)) { $score = 10; } else { $score = 0; } return ['code'=>0, 'msg'=>'', 'data'=>$score]; } /** * 计算负分和最近访问 * @param $user * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateNegativeScore($user, $send_user) { try { //计算负面分 $negative_res = $this->calculateNegative($send_user); if ($negative_res['code']) return $negative_res; $negative_score = $negative_res['data']; $visit_res = $this->calculateVisit($user, $send_user); //计算访问扣除分数 if ($visit_res['code']) return $visit_res; $visit_score = $visit_res['data']; $score = $negative_score + $visit_score; return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算userId=' . $user->id . ',sendUserId=' . $send_user->id . '计算负分和最近访问出错,请及时处理!!!,']; } } /** * 计算负分 * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateNegative($send_user) { try { $score = $send_user->negative_score; return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算userId=' . $send_user->id . ',负分出错,请及时处理!!!,']; } } /** * 计算访问扣除分数 * @param $user * @param $send_user * @return array * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function calculateVisit($user, $send_user) { try { //最近访问 $score = 0; /*$preview_key = 'ai:preview:'.$user->id; $log = Redis::get($preview_key); if ($log){ $log_arr = json_decode($log, true); $result = in_array($send_user->id, $log_arr); if ($result) return $score = -50; } */ $log = $this->getReview($user->id); if ($log) { if (in_array($send_user->id, $log)) { $score -= 5; } } //列表刷新 $browse = $this->getBrowse($user->id); if ($browse) { if (in_array($send_user->id, $browse)) { $score -= 3; } } return ['code'=>0, 'msg'=>'', 'data'=>$score]; } catch (Exception $e) { return ['code'=>1, 'msg'=>'计算userId=' . $user->id . ',sendUserId=' . $send_user->id . '访问扣除分数出错,请及时处理!!!,']; } } public function getReview($id) { if (isset(self::$static_ai_reviews[$id])) { return self::$static_ai_reviews[$id]; } else { return false; } } /** * 获取浏览记录缓存 * @param $id * @return false|mixed */ public function getBrowse($id) { if (isset(self::$static_ai_browses[$id])) { return self::$static_ai_browses[$id]; } else { return false; } } /** * 计算两个坐标的距离 * @param $lng1 , $lng2 经度 * @param $lat1 , $lat2 纬度 * @param int $unit 单位 1:米 2:千米 * @param int $decimal 精度 保留小数位数 */ function getDistance($lng1, $lat1, $lng2, $lat2, $unit = 1, $decimal = 2) { $earthdata = 6371;//地球半径,平均半径为6371km // 将角度转为狐度 $radLat1 = deg2rad($lat1); //deg2rad()函数将角度转换为弧度 $radLat2 = deg2rad($lat2); $radLng1 = deg2rad($lng1); $radLng2 = deg2rad($lng2); $dlat = $radLat1 - $radLat2; $dlng = $radLng1 - $radLng2; $length = 2 * asin(sqrt(pow(sin($dlat / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($dlng / 2), 2))) * $earthdata * 1000; if ($unit == 2) { $length /= 1000; } $length = round($length, $decimal); return $length; } /** * 修改缓存分数 * @param $user * @param $send_user * @param $base_score * @param $dynamic_score * @param $negative_score * @return bool * @throws \Calchen\LaravelDingtalkRobot\Exceptions\Exception */ public function updateCacheScore($user, $send_user, $base_score, $dynamic_score, $negative_score) { try { $recommend_user_key = 'ai:recmd:scores:' . $user->id; $is_recommend = $base_score == 150 ? 1 : 0; $score = $base_score + $dynamic_score - $negative_score; $log = ['send_user' => $send_user->id, 'is_recommend' => $is_recommend, 'score' => $score, 'base_score' => $base_score, 'dync_score' => $dynamic_score, 'negative_score' => $negative_score]; $json_recommend = json_encode($log); $recommend_log = Redis::set($recommend_user_key, $json_recommend); return true; } catch (Exception $e) { return false; } } /** * 年龄转成时间 * @param $age * @param string $symbol * @return string */ public function ageToBirthday($age, $symbol = '-') { $age = $age == 0 ? 25 : $age; $nowyear = date("Y", time()); $year = $nowyear - $age; $monthArr = []; for ($i = 1; $i < 13; $i++) { $monthArr[] = $i < 10 ? '0' . $i : $i; } $dayArr = []; for ($i = 1; $i < 29; $i++) { $dayArr[] = $i < 10 ? '0' . $i : $i; } $month_key = array_rand($monthArr, 1); $month = $monthArr[$month_key]; $date_tmp_stamp = strtotime($year . '-' . $month); $day = ''; if ($month == '02' && date("t", $date_tmp_stamp) == '29') { $dayArr = array_merge($dayArr, ['29']); $day_key = array_rand($dayArr, 1); $day = $dayArr[$day_key]; } else if ($month == '02' && date("t", $date_tmp_stamp) == '28') { $day_key = array_rand($dayArr, 1); $day = $dayArr[$day_key]; } else if (in_array($month, ['01', '03', '05', '07', '08', '10', '12'])) { $dayArr = array_merge($dayArr, ['29', '30', '31']); $day_key = array_rand($dayArr, 1); $day = $dayArr[$day_key]; } else { $dayArr = array_merge($dayArr, ['29', '30']); $day_key = array_rand($dayArr, 1); $day = $dayArr[$day_key]; } return $year . $symbol . $month . $symbol . $day; } }