123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867 |
- <?php
- /**
- * Created by PhpStorm.
- * User: stanley-king
- * Date: 2016/10/7
- * Time: 下午12:44
- */
- namespace search;
- use algorithm;
- use brand_helper;
- use category_helper;
- use Log;
- use special_manager;
- use commonid_helper;
- class brand_dict extends indexer
- {
- private $mBrandCommon;
- private $mBrandHots;
- public function __construct()
- {
- parent::__construct();
- $this->mBrandCommon = new one_multi();
- $this->mBrandHots = new one_multi();
- $this->init();
- }
- private function init()
- {
- $brands_info = brand_helper::instance()->brandex(); //todo 确认一下
- $brands = $brands_info['brands'];
- foreach ($brands as $item)
- {
- $name = $item['brand_name'];
- $bid = intval($item['brand_id']);
- $this->parase($name,$bid);
- }
- }
- public function commons($brand_id)
- {
- return $this->mBrandCommon->get($brand_id);
- }
- public function hots($brand_id) {
- return $this->mBrandHots->get($brand_id);
- }
- public function add_brand($brand_id, $common_id, $hot_id)
- {
- $this->mBrandCommon->add($brand_id,$common_id);
- $this->mBrandHots->add($brand_id,$hot_id);
- }
- }
- class category_dict extends indexer
- {
- private $mGcHot; //一个GC对应一个HotID
- private $mHoTree; //HOT的父子关系
- private $mHotBrand;
- private $mHotCommon;
- public function __construct()
- {
- parent::__construct();
- $this->mGcHot = new one_one();
- $this->mHoTree = new parent_sub_tree();
- $this->mHotBrand = new one_multi();
- $this->mHotCommon = new one_multi();
- $this->init();
- }
- public function init()
- {
- $cats = category_helper::instance()->categories();
- foreach ($cats as $item)
- {
- $hot_id = intval($item['hot_id']);
- $this->mHoTree->add($hot_id,0);
- $name = $item['name'];
- $this->parase($name,$hot_id);
- foreach($item['subitem'] as $sub_item) {
- $subhot_id = intval($sub_item['hot_id']);
- $this->mHoTree->add($subhot_id,$hot_id);
- $cids = category_helper::instance()->cids($subhot_id);
- $this->add_gc_hot($cids,$subhot_id);
- $subname = $sub_item['name'];
- $this->parase($subname,$subhot_id);
- }
- }
- }
- public function brands($hotid)
- {
- if($this->mHoTree->is_parent($hotid) == false) {
- return $this->mHotBrand->get($hotid);
- }
- else
- {
- $sub_hots = $this->mHoTree->subs($hotid);
- $pos = 0;
- $brands = [];
- foreach ($sub_hots as $hot)
- {
- if($pos == 0) {
- $brands = $this->mHotBrand->get($hot);
- } else {
- $tmp = $this->mHotBrand->get($hot);
- $brands = algorithm::set_union($brands,$tmp);
- }
- $pos++;
- }
- return $brands;
- }
- }
- public function commons($hotid)
- {
- if($this->mHoTree->is_parent($hotid) == false) {
- return $this->mHotCommon->get($hotid);
- }
- else
- {
- $sub_hots = $this->mHoTree->subs($hotid);
- $pos = 0;
- $cids = [];
- foreach ($sub_hots as $hot)
- {
- if($pos == 0) {
- $cids = $this->mHotCommon->get($hot);
- } else {
- $tmp = $this->mHotCommon->get($hot);
- $cids = algorithm::set_union($cids,$tmp);
- }
- $pos++;
- }
- return $cids;
- }
- }
- public function add_hot($hotid,$brand,$common)
- {
- $this->mHotBrand->add($hotid,$brand);
- $this->mHotCommon->add($hotid,$common);
- }
- public function hotid($gc_id) {
- return $this->mGcHot->get($gc_id);
- }
- private function add_gc_hot($gc_ids,$hot_id)
- {
- foreach ($gc_ids as $cid) {
- $cid = intval($cid);
- $this->mGcHot->add($cid,$hot_id);
- }
- }
- }
- class goods_dict extends indexer
- {
- private $cid_brands;
- private $cid_hots;
- public function __construct()
- {
- parent::__construct();
- $this->cid_brands = new one_one();
- $this->cid_hots = new one_one();
- }
- public function add_goods($common_id,$brand,$hot) {
- $this->cid_brands->add($common_id,$brand);
- $this->cid_hots->add($common_id,$hot);
- }
- public function hots($cids)
- {
- $values = [];
- foreach ($cids as $cid) {
- $hot = $this->cid_hots->get($cid);
- if(algorithm::binary_search($values,$hot) == false) {
- $pos = algorithm::lower_bonud($values,$hot);
- algorithm::array_insert($values,$pos,$hot);
- }
- }
- return $values;
- }
- public function brands($cids)
- {
- $values = [];
- foreach ($cids as $cid) {
- $brand = $this->cid_brands->get($cid);
- if(algorithm::binary_search($values,$brand) == false) {
- $pos = algorithm::lower_bonud($values,$brand);
- algorithm::array_insert($values,$pos,$brand);
- }
- }
- return $values;
- }
- }
- class special_dict extends indexer
- {
- private $spid_names;
- public function __construct()
- {
- parent::__construct();
- $this->spid_names = new one_one();
- $this->init();
- }
- private function init()
- {
- $mod_special = Model();
- $i = 0;
- while (true)
- {
- $start = $i * 1000;
- $items = $mod_special->table('mb_special')
- ->field('*')
- ->where(['special_id' => ['gt', 0],'state' => 0,'reader_type' => 0])
- ->order('special_id asc')
- ->limit("{$start},1000")
- ->select();
- $i++;
- if (empty($items)) {
- break;
- }
- else
- {
- foreach ($items as $item)
- {
- $spid = intval($item['special_id']);
- $keywords = $item['keywords'];
- $title = $item['share_title'];
- if(!empty($keywords)) {
- $this->parase($keywords,$spid);
- $this->parase($title,$spid);
- $this->spid_names->add($spid,$title);
- }
- }
- }
- }
- }
- public function name($val)
- {
- return $this->spid_names->get($val);
- }
- }
- class goods_info
- {
- private $mGoods;
- public function __construct()
- {
- $this->mGoods = [];
- }
- public function add($commonid, $price, $click, $salenum)
- {
- $commonid = intval($commonid);
- if(!array_key_exists($commonid,$this->mGoods)) {
- $this->mGoods[$commonid]['price'] = intval($price * 100 + 0.5);
- $this->mGoods[$commonid]['click'] = intval($click);
- $this->mGoods[$commonid]['salenum'] = intval($salenum);
- }
- }
- public function goods($commonid)
- {
- return $this->mGoods[$commonid];
- }
- static public function click_asc($left,$right)
- {
- $t_l = intval($left['click']);
- $t_r = intval($right['click']);
- if($t_l > $t_r) return 1;
- elseif($t_l < $t_r) return -1;
- else return 0;
- }
- static public function click_desc($left,$right)
- {
- $t_l = intval($left['click']);
- $t_r = intval($right['click']);
- if($t_l > $t_r) return -1;
- elseif($t_l < $t_r) return 1;
- else return 0;
- }
- static public function salenum_asc($left,$right)
- {
- $t_l = intval($left['salenum']);
- $t_r = intval($right['salenum']);
- if($t_l > $t_r) return 1;
- elseif($t_l < $t_r) return -1;
- else return 0;
- }
- static public function salenum_desc($left,$right)
- {
- $t_l = intval($left['salenum']);
- $t_r = intval($right['salenum']);
- if($t_l > $t_r) return -1;
- elseif($t_l < $t_r) return 1;
- else return 0;
- }
- static public function price_asc($left,$right)
- {
- $t_l = intval($left['price']);
- $t_r = intval($right['price']);
- if($t_l > $t_r) return 1;
- elseif($t_l < $t_r) return -1;
- else return 0;
- }
- static public function price_desc($left,$right)
- {
- $t_l = intval($left['price']);
- $t_r = intval($right['price']);
- if($t_l > $t_r) return -1;
- elseif($t_l < $t_r) return 1;
- else return 0;
- }
- }
- class searcher
- {
- const filter = "goods_commonid,gc_id,brand_id,goods_mobile_name,goods_jingle,goods_spec,goods_click,goods_salenum,goods_price";
- private $name_dict;
- private $jingle_dict;
- private $spec_dict;
- private $special_dict;
- private $brand_dict;
- private $category_dict;
- private $goods_dict;
- private $goods_info;
- private $price_cids;
- private $promot_cids;
- private static $stInstance;
- public static function instance()
- {
- if(self::$stInstance == null) {
- self::$stInstance = new searcher();
- }
- return self::$stInstance;
- }
- private function get_spec($arSpec)
- {
- $specs = unserialize($arSpec);
- if(isset($specs) && is_array($specs))
- {
- $spec_val = '';
- foreach ($specs as $key => $val) {
- $spec_val .= " ";
- $spec_val .= $val;
- }
- return trim($spec_val);
- } else {
- return "";
- }
- }
- public function init()
- {
- $this->brand_dict = new brand_dict();
- $this->category_dict = new category_dict();
- $this->name_dict = new indexer();
- $this->jingle_dict = new indexer();
- $this->spec_dict = new indexer();
- $this->goods_dict = new goods_dict();
- $this->goods_info = new goods_info();
- $this->price_cids = new valtokey();
- $this->special_dict = new special_dict();
- $this->promot_cids = [];
- $mod_goods = Model('goods');
- global $config;
- $exbrands = $config['exclude_brands'];
- if(!empty($exbrands)) {
- $items = $mod_goods->getGoodsOnlineList(['brand_id' => ['not in',$exbrands]], self::filter, '', '', false);
- } else {
- $items = $mod_goods->getGoodsOnlineList([], self::filter, '', '', false);
- }
- $count = count($items);
- $index = 1;
- foreach ($items as $item)
- {
- Log::record("{$index} / {$count}",Log::DEBUG);
- $index++;
- $common_id = intval($item['goods_commonid']);
- $gc_id = intval($item['gc_id']);
- $brand_id = intval($item['brand_id']);
- $hot_id = intval($this->category_dict->hotid($gc_id));
- $this->name_dict->parase($item['goods_mobile_name'],$common_id);
- $this->jingle_dict->parase($item['goods_jingle'],$common_id);
- $spec = $this->get_spec($item['goods_spec']);
- if(!empty($spec)) {
- $this->spec_dict->parase($spec,$common_id);
- $this->goods_dict->parase($spec,$common_id);
- }
- $this->goods_dict->parase($item['goods_mobile_name'],$common_id);
- $this->goods_dict->parase($item['goods_jingle'],$common_id);
- $this->brand_dict->add_brand($brand_id,$common_id,$hot_id);
- $this->goods_dict->add_goods($common_id,$brand_id,$hot_id);
- $this->category_dict->add_hot($hot_id,$brand_id,$common_id);
- $this->goods_info->add($common_id,$item['goods_price'],$item['goods_click'],$item['goods_salenum']);
- $this->price_cids->add($common_id,intval($item['goods_price'] * 100 + 0.5));
- }
- $this->price_cids->finish();
- $this->read_promotion();
- }
- private function read_promotion()
- {
- global $config;
- $special = $config['bonus_match_goods'];
- if(empty($special)) return false;
- $special_id = intval($special['special_id']);
- if($special_id <= 0) return false;
- special_manager::instance()->special($special_id,$goods_ids);
- if(empty($goods_ids)) return false;
- $cids = [];
- foreach ($goods_ids as $gid) {
- $cid = commonid_helper::instance()->common_id($gid);
- if($cid != false) {
- $cids[] = $cid;
- }
- }
- sort($cids);
- $this->promot_cids = $cids;
- return true;
- }
- private function get_name($dict, $words)
- {
- if(empty($words)) {
- return array();
- }
- $ids = $this->get_ids($dict, $words);
- $result = [];
- foreach ($ids as $id)
- {
- $name = $dict->name($id);
- if($name != false) {
- $result[] = $name;
- }
- }
- return $result;
- }
- public function get_word($input)
- {
- $words = word_segment::filter($input);
- if(empty($words)) return false;
- $goods_name = $this->get_name($this->name_dict,$words);
- $jingle_name = $this->get_name($this->jingle_dict,$words);
- $spec_name = $this->get_name($this->spec_dict,$words);
- $brands = $this->get_name($this->brand_dict,$words);
- $cats = $this->get_name($this->category_dict,$words);
- $specials = $this->get_name($this->special_dict,$words);
- $result = array_merge($brands,$cats,$specials,$spec_name,$goods_name,$jingle_name);
- return $result;
- }
- public function keyword($keyword)
- {
- if(empty($keyword)) return false;
- $words = word_segment::filter($keyword);
- if(empty($words)) return [];
- $cids = $this->get_ids($this->goods_dict,$words);
- $brands = $this->get_ids($this->brand_dict,$words);
- foreach ($brands as $brand_id) {
- $tmp = $this->brand_dict->commons($brand_id);
- $cids = algorithm::set_union($cids,$tmp);
- }
- $cats = $this->get_ids($this->category_dict,$words);
- foreach ($cats as $hot_id) {
- $tmp = $this->category_dict->commons($hot_id);
- $cids = algorithm::set_union($cids,$tmp);
- }
- return $cids;
- }
- private function format($cids,$bids,$hotids,$spids)
- {
- if(empty($cids)) {
- return [];
- }
- $brands = [];
- if(!empty($bids))
- {
- foreach ($bids as $bid)
- {
- $title = $this->brand_dict->name($bid);
- if($title != false) {
- $item['title'] = $title;
- $item['data'] = $bid;
- $item['type'] = 'brand';
- $brands[] = $item;
- }
- }
- }
- $hots = [];
- if(!empty($hotids))
- {
- foreach ($hotids as $hot)
- {
- $title = $this->category_dict->name($hot);
- if($title != false) {
- $item['title'] = $title;
- $item['data'] = $hot;
- $item['type'] = 'category';
- $hots[] = $item;
- }
- }
- }
- return ['cids' => $cids,'brands' => $brands,'hots' => $hots,'spids' => $spids];
- }
- private function keyword_serarch($keyword, $hot, $brand)
- {
- $cids = $this->keyword($keyword);
- if($brand > 0) {
- $brand_name = brand_helper::instance()->name($brand);
- } else {
- $brand_name = '';
- }
- if($hot > 0) {
- $hot_name = category_helper::instance()->name($hot);
- } else {
- $hot_name = '';
- }
- $keywords = $keyword . $brand_name . $hot_name;
- $spids = $this->get_ids($this->special_dict,word_segment::filter($keywords));
- if(empty($cids)) {
- return $this->format($cids,null,null,$spids);
- }
- if($brand != 0)
- {
- $bcids = $this->brand_dict->commons($brand);
- $cids = algorithm::set_intersection($cids,$bcids);
- if(empty($cids)) {
- return $this->format($cids,null,null,$spids);
- }
- if($hot != 0)
- {
- $hcids = $this->category_dict->commons($hot);
- $cids = algorithm::set_intersection($cids,$hcids);
- if(empty($cids)) {
- return $this->format($cids,null,null,$spids);
- } else {
- return $this->format($cids,null,null,$spids);
- }
- }
- else {
- $hots = $this->goods_dict->hots($cids);
- return $this->format($cids,null,$hots,$spids);
- }
- }
- else
- {
- if($hot != 0)
- {
- $hcids = $this->category_dict->commons($hot);
- $cids = algorithm::set_intersection($cids, $hcids);
- if (empty($cids)) {
- return array();
- } else {
- $brands = $this->goods_dict->brands($cids);
- return $this->format($cids,$brands,null,$spids);
- }
- }
- else
- {
- $brands = $this->goods_dict->brands($cids);
- return $this->format($cids,$brands,null,$spids);
- }
- }
- }
- private function hb_search($hot,$brand)
- {
- if($brand > 0) {
- $brand_name = brand_helper::instance()->name($brand);
- } else {
- $brand_name = '';
- }
- if($hot > 0) {
- $hot_name = category_helper::instance()->name($hot);
- } else {
- $hot_name = '';
- }
- $keywords = $brand_name . $hot_name;
- $spids = $this->get_ids($this->special_dict,word_segment::filter($keywords));
- if($brand != 0)
- {
- $cids = $this->brand_dict->commons($brand);
- if(empty($cids)) return array();
- if($hot != 0)
- {
- $hcids = $this->category_dict->commons($hot);
- $cids = algorithm::set_intersection($cids,$hcids);
- if(empty($cids)) {
- return array();
- }
- else {
- return $this->format($cids,null,null,$spids);
- }
- } else {
- $hots = $this->goods_dict->hots($cids);
- return $this->format($cids,null,$hots,$spids);
- }
- }
- else
- {
- if($hot != 0)
- {
- $cids = $this->category_dict->commons($hot);
- if(empty($cids)) {
- return array();
- } else {
- $brands = $this->goods_dict->brands($cids);
- return $this->format($cids,$brands,null,$spids);
- }
- } else {
- return array();
- }
- }
- }
- public function get_result($params)
- {
- $keyword = $params['keyword'];
- $brand = $params['brand_id'];
- $hot = $params['hot_id'];
- if(empty($keyword) && $brand == 0 && $hot == 0) {
- return array();
- }
- if(isset($keyword) && !empty($keyword)) {
- $result = $this->keyword_serarch($keyword,$hot,$brand);
- } else {
- $result = $this->hb_search($hot,$brand);
- }
- if(!empty($result))
- {
- $order = $params['order'];
- $sort = $params['sort'];
- $page_count = 1;
- if(!isset($params['page_no'])) {
- $page_no = null;
- } else {
- $page_no = $params['page_no'];
- }
- if(!isset($params['page_size'])) {
- $page_size = null;
- } else {
- $page_size = intval($params['page_size']);
- $page_size = $page_size <= 0 ? 10 : $page_size;
- $page_count = intval(count($result['cids']) / $page_size) + ((count($result['cids']) % $page_size) == 0 ? 0 : 1);
- }
- $cids = $this->sort_goods($result['cids'],$order,$sort,$page_no,$page_size);
- $result['cids'] = $cids;
- $result['page_count'] = $page_count;
- }
- return $result;
- }
- private function sort_goods($cids,$order,$sort,$page_no,$page_size)
- {
- $goods = [];
- foreach ($cids as $cid) {
- $val = $this->goods_info->goods($cid);
- $val['cid'] = $cid;
- $goods[] = $val;
- }
- if($sort == 'asc')
- {
- if($order == 'click') {
- uasort($goods,['\search\goods_info','click_asc']);
- }
- elseif($order == 'salenum') {
- uasort($goods,['\search\goods_info','salenum_asc']);
- }
- elseif($order == 'price') {
- uasort($goods,['\search\goods_info','price_asc']);
- }
- else {
- Log::record("searcher sort_goods not order param");
- }
- }
- else
- {
- if($order == 'click') {
- uasort($goods,['\search\goods_info','click_desc']);
- }
- elseif($order == 'salenum') {
- uasort($goods,['\search\goods_info','salenum_desc']);
- }
- elseif($order == 'price') {
- uasort($goods,['\search\goods_info','price_desc']);
- }
- else {
- Log::record("searcher sort_goods not order param");
- }
- }
- $tmp = [];
- foreach ($goods as $val) {
- $tmp[] = $val;
- }
- $goods = $tmp;
- $count = count($goods);
- $result = [];
- if($page_no == null || $page_size == null)
- {
- foreach ($goods as $val) {
- $result[] = $val['cid'];
- }
- }
- else
- {
- $page_no = $page_no <= 0 ? 1 : $page_no;
- for ($start = ($page_no -1) * $page_size; $page_size > 0 && $start < $count; $page_size--,$start++) {
- $result[] = $goods[$start]['cid'];
- }
- }
- return $result;
- }
- public function match_price($params)
- {
- $price = $params['price'];
- $page_no = intval($params['page_no']);
- $page_size = intval($params['page_size']);
- if($page_no <= 0 || $page_size <= 0) {
- return false;
- }
- $start = ($page_no - 1) * $page_size;
- $result = $this->price_cids->findless(intval($price * 100 + 0.5),$start,$page_size);
- $result['page_count'] = intval($result['total'] / $page_size) + ($result['total'] % $page_size == 0 ? 0 : 1);
- return $result;
- }
- public function promote_goods($params)
- {
- $price = $params['price'];
- $count = intval($params['count']);
- $items = $this->price_cids->findall(intval($price * 100 + 0.5));
- sort($items);
- $match_cids = $items;
- $pro_cids = algorithm::set_intersection($match_cids,$this->promot_cids);
- if(count($pro_cids) < $count) {
- $cids = $this->random_goods($match_cids,$count);
- } else {
- $cids = $this->random_goods($pro_cids,$count);
- }
- return ['total' => 1,'cids' => $cids,'total' => count($cids)];
- }
- private function random_goods($cids,$count)
- {
- $length = count($cids);
- if($length <= $count) return $cids;
- $result = [];
- for ($i = 0; $i < $count;)
- {
- $pos = mt_rand(0,$length - 1);
- $val = $cids[$pos];
- if(!in_array($val,$result)) {
- $result[] = $val;
- $i++;
- }
- }
- return $result;
- }
-
- private function get_ids($dict, $words)
- {
- $i = 0;
- $ids = [];
- foreach ($words as $word)
- {
- $tmp = $dict->find($word);
- if ($i == 0) {
- $ids = $tmp;
- } else {
- $ids = algorithm::set_intersection($tmp, $ids);
- if (empty($ids)) break;
- }
- ++$i;
- }
- return $ids;
- }
- }
|