提交 7b68a9c3 编写于 作者: R root

catalog product search : chinese lang search by XunSearch

上级 104cd7ab
......@@ -28,7 +28,7 @@ return [
'search_query' =>[
# 放到第一个的就是默认值,譬如下面的30
'numPerPage' => [4,30,60,90], # 产品显示个数的列举
'numPerPage' => [30,60,90], # 产品显示个数的列举
# 价格区间设置,如果不想在搜索页面价格过滤,可以清空这个。
'price_range' => [
......
......@@ -24,54 +24,6 @@ class IndexController extends AppfrontController
# 网站信息管理
public function actionIndex()
{
/*
$model = new Search;
$model->pid = 341234;
$model->name = '小米手机';
$model->description = '小米手机Air采用了全尺寸的背光键盘,在接口方面拥有不错的扩展性。因为采用了无logo设计,小米官方会推出名画以及当代艺术家的画作的贴纸,还推出了笔记本包。';
$model->save();
$model = new Search;
$model->pid = 44444;
$model->name = '北京小米科技有限责任公司';
$model->description = '北京小米科技有限责任公司成立2010年4月,是一家专注于智能硬件和电子产品研发的移动互联网公司。“为发烧而生”是小米的产品概念。小米公司首创了用互联网模式开发手机操作系统、发烧友参与开发改进的模式。
2014年12月14日晚,美的集团发出公告称,已与小米科技签署战略合作协议,小米12.7亿元入股美的集团。2015年9月22日,小米在北京发布了新品小米4c,这款新品由小米4i升级而来,配备5英寸显示屏,搭载骁龙808处理器,号称安卓小王子。
2016年7月27日的发布会上小米笔记本终于正式亮相,这款产品叫做小米笔记本Air。';
$model->save();
*/
echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
$query = Search::find();
$condition = '小米手机';
$data = $query->asArray()->limit(100) //->where($condition)
->all();
foreach($data as $d){
var_dump($d);
echo '<br>####################<br>';
}
exit;
/*
Yii::$service->search->initFullSearchIndex();
$filter['select'] = ['_id'];
$count = Yii::$service->product->collCount($filter);
//echo $count;
$numPerPage = 10;
$pageCount = ceil($count/10);
for($i=1;$i<=$pageCount;$i++){
$filter['numPerPage'] = $numPerPage;
$filter['pageNum'] = $i;
$products = Yii::$service->product->coll($filter);
$product_ids = [];
foreach($products['coll'] as $p){
$product_ids[] = $p['_id'];
}
//var_dump($product_ids);exit;
Yii::$service->search->syncProductInfo($product_ids);
}
*/
$data = $this->getBlock()->getLastData();
return $this->render($this->action->id,$data);
......
......@@ -86,15 +86,7 @@
<div class="top_main_inner pr">
<div class="top_header clearfix">
<div class="topSeachForm">
<form method="get" name="searchFrom" class="js_topSeachForm" action="<?= Yii::$service->url->getUrl('catalogsearch/index'); ?>">
<div class="top_seachBox">
<div class="searchInput fl">
<input type="text" value="<?= Yii::$app->request->get('q'); ?>" maxlength="150" placeholder="Products keyword" class="searchArea js_k2 ac_input" name="q">
</div>
<button class="fl js_topSearch seachBtn" type="submit"><span class="t_hidden">search</span></button>
<!-- <input type="hidden" class="category" value="0" name="category"> -->
</div><!--end .top_seachBox-->
</form>
<?= Yii::$service->page->widget->render('topsearch',$this); ?>
</div>
<div class="logo"><a titel="fecshop logo" href="<?= $homeUrl ?>" style="">
......
<form method="get" name="searchFrom" class="js_topSeachForm" action="<?= Yii::$service->url->getUrl('catalogsearch/index'); ?>">
<div class="top_seachBox">
<div class="searchInput fl">
<input type="text" value="<?= Yii::$app->request->get('q'); ?>" maxlength="150" placeholder="Products keyword" class="searchArea js_k2 ac_input" name="q">
</div>
<button class="fl js_topSearch seachBtn" type="submit"><span class="t_hidden">search</span></button>
<!-- <input type="hidden" class="category" value="0" name="category"> -->
</div><!--end .top_seachBox-->
</form>
\ No newline at end of file
......@@ -88,6 +88,11 @@ class SearchController extends Controller
public function actionDeletenotactiveproduct($nowTimeStamp){
Yii::$service->search->deleteNotActiveProduct($nowTimeStamp);
}
public function actionXundeleteallproduct($i){
Yii::$service->search->xunSearch->xunDeleteAllProduct($this->_numPerPage,$i);
}
}
......
......@@ -8,9 +8,11 @@
return [
'search' => [
'class' => 'fecshop\services\Search',
/* example:
'filterAttr' => [
'color','size', # 在搜索页面侧栏的搜索过滤属性字段
],
*/
'childService' => [
'mongoSearch' => [
'class' => 'fecshop\services\search\MongoSearch',
......@@ -18,6 +20,8 @@ return [
'name' => 10,
'description' => 5,
],
#more : https://docs.mongodb.com/manual/reference/text-search-languages/#text-search-languages
/* example:
'searchLang' => [
'en' => 'english',
'fr' => 'french',
......@@ -26,6 +30,7 @@ return [
'ru' => 'russian',
'pt' => 'portuguese',
],
*/
],
'xunSearch' => [
'class' => 'fecshop\services\search\XunSearch',
......@@ -33,6 +38,8 @@ return [
'name' => 10,
'description' => 5,
],
'fuzzy' => true, # 是否开启模糊查询
'synonyms' => true, #是否开启同义词翻译
'searchLang' => ['zh'],
],
],
......
......@@ -71,9 +71,9 @@ index = none
[color]
type = string
index = none
index = self
[size]
type = string
index = none
index = self
\ No newline at end of file
......@@ -17,6 +17,6 @@ use yii\db\ActiveRecord;
class Search extends \hightman\xunsearch\ActiveRecord
{
public static function projectName() {
return 'search'; // ⽫ʹ @app/config/another_name.ini ΪĿ
return 'search'; // 这将使用 @app/config/another_name.ini 作为项目名
}
}
\ No newline at end of file
......@@ -10,8 +10,8 @@ namespace fecshop\services\search;
use Yii;
use yii\base\InvalidValueException;
use yii\base\InvalidConfigException;
use fecshop\models\mongodb\Search;
use fecshop\services\Service;
use fecshop\models\mongodb\Product;
use fecshop\models\xunsearch\Search as XunSearchModel;
/**
* Search
......@@ -22,6 +22,8 @@ class XunSearch extends Service implements SearchInterface
{
public $searchIndexConfig;
public $searchLang;
public $fuzzy = false;
public $synonyms = false;
/**
* 初始化xunSearch索引
*/
......@@ -32,10 +34,11 @@ class XunSearch extends Service implements SearchInterface
* 将产品信息同步到xunSearch引擎中
*/
protected function actionSyncProductInfo($product_ids,$numPerPage){
if(is_array($product_ids) && !empty($product_ids)){
$productPrimaryKey = Yii::$service->product->getPrimaryKey();
$searchModel = new Search;
$filter['select'] = $searchModel->attributes();
$XunSearchModel = new XunSearchModel;
$filter['select'] = $XunSearchModel->attributes();
$filter['asArray'] = true;
$filter['where'][] = ['in',$productPrimaryKey,$product_ids];
$filter['numPerPage']= $numPerPage;
......@@ -54,6 +57,7 @@ class XunSearch extends Service implements SearchInterface
$one['description'] = Yii::$service->fecshoplang->getLangAttrVal($one_description,'description',$langCode);
$one['short_description'] = Yii::$service->fecshoplang->getLangAttrVal($one_short_description,'short_description',$langCode);
$one['sync_updated_at'] = time();
//echo $one['sync_updated_at']."\n";
$serialize = true;
Yii::$service->helper->ar->save($XunSearchModel,$one,$serialize);
if($errors = Yii::$service->helper->errors->get()){
......@@ -69,12 +73,31 @@ class XunSearch extends Service implements SearchInterface
}
return true;
}
/**
* 批量更新过程中,被更新的产品都会更新字段sync_updated_at
* 删除xunSearch引擎中sync_updated_at小于$nowTimeStamp的字段
*/
protected function actionDeleteNotActiveProduct($nowTimeStamp){
return;
}
/**
* 删除在xunSearch的所有搜索数据,
* 当您的产品有很多产品被删除了,但是在xunsearch 存在某些异常没有被删除
* 您希望也被删除掉,那么,你可以通过这种方式批量删除掉产品
* 然后重新跑一边同步脚本
*/
protected function actionXunDeleteAllProduct($numPerPage,$i){
//var_dump($index);
$dbName = XunSearchModel::projectName();
# 删除索引
Yii::$app->xunsearch->getDatabase($dbName)->getIndex()->clean();
//$index = Yii::$app->xunsearch->getDatabase($dbName)->index;
echo "begin delete Xun Search Date \n";
$nowTimeStamp = (int) $nowTimeStamp;
$XunSearchData = XunSearchModel::find()
->limit($numPerPage)
->offset(($i-1)*$numPerPage)
->all();
foreach($XunSearchData as $one){
$one->delete();
}
}
/**
......@@ -82,21 +105,134 @@ class XunSearch extends Service implements SearchInterface
*/
protected function actionGetSearchProductColl($select,$where,$pageNum,$numPerPage,$product_search_max_count){
$collection = $this->fullTearchText($select,$where,$pageNum,$numPerPage,$product_search_max_count);
$collection['coll'] = Yii::$service->category->product->convertToCategoryInfo($collection['coll']);
//var_dump($collection);
//exit;
return $collection;
}
protected function fullTearchText($select,$where,$pageNum,$numPerPage,$product_search_max_count){
$XunSearchQuery = XunSearchModel::find()->asArray();
$XunSearchQuery->fuzzy($this->fuzzy);
$XunSearchQuery->synonyms($this->synonyms);
if(is_array($where) && !empty($where)){
if(isset($where['$text']['$search']) && $where['$text']['$search']){
$XunSearchQuery->where($where['$text']['$search']);
}else{
return [];
}
foreach($where as $k => $v){
if($k != '$text'){
$XunSearchQuery->andWhere([$k => $v]);
}
}
}
$XunSearchQuery->orderBy( ['score' => SORT_DESC] );
$XunSearchQuery->limit($product_search_max_count);
$XunSearchQuery->offset(0);
$search_data = $XunSearchQuery->all();
$data = [];
foreach($search_data as $one){
if(!isset($data[$one['spu']])){
$data[$one['spu']] = $one;
}
}
$count = count($data);
$offset = ($pageNum -1)*$numPerPage;
$limit = $numPerPage;
$productIds = [];
foreach($data as $d){
$productIds[] = new \MongoId($d['_id']);
}
$productIds = array_slice($productIds, $offset, $limit);
if(!empty($productIds)){
$query = Product::find()->asArray()
->select($select)
->where(['_id'=> ['$in'=>$productIds]])
;
$data = $query->all();
/**
* 下面的代码的作用:将结果按照上面in查询的顺序进行数组的排序,使结果和上面的搜索结果排序一致(_id)。
*/
$s_data = [];
foreach($data as $one){
$_id = $one['_id']->{'$id'};
$s_data[$_id] = $one;
}
$return_data = [];
foreach($productIds as $product_id){
$return_data[] = $s_data[$product_id->{'$id'}];
}
return [
'coll' => $return_data ,
'count'=> $count,
];
}
}
/**
* 得到搜索的sku列表侧栏的过滤
*/
protected function actionGetFrontSearchFilter($filter_attr,$where){
//var_dump($where);
$dbName = XunSearchModel::projectName();
$_search = Yii::$app->xunsearch->getDatabase($dbName)->getSearch();
$text = isset($where['$text']['$search']) ? $where['$text']['$search'] : '';
if(!$text){
return [];
}
$sh = '';
foreach($where as $k => $v){
if($k != '$text'){
if(!$sh){
$sh = ' AND '.$k.':'.$v;
}else{
$sh .= ' AND '.$k.':'.$v;
}
}
}
echo $sh;
$docs = $_search->setQuery($text.$sh)
->setFacets([$filter_attr])
->setFuzzy($this->fuzzy)
->setAutoSynonyms($this->synonyms)
->search();
$filter_attr_counts = $_search->getFacets($filter_attr);
$count_arr = [];
if(is_array($filter_attr_counts) && !empty($filter_attr_counts)){
foreach($filter_attr_counts as $k => $v){
$count_arr[] = [
'_id' => $k,
'count' => $v,
];
}
}
return $count_arr;
}
/**
* 通过product_id删除搜索数据
*/
protected function actionRemoveByProductId($product_id){
if(is_object($product_id)){
$product_id = $product_id->{'$id'};
$model = XunSearchModel::findOne($product_id);
$model->delete();
}
}
......
......@@ -22,7 +22,14 @@ done
#delete all search data that sync_updated_at $gt $nowtime.
$Cur_Dir/../../../../yii product/search/deletenotactiveproduct $nowtime
###### 1.Sync Section End
###### delete xunsearch
echo "There are $pagenum pages to check if is delete in xunSearch"
echo "##############ALL BEGINING###############";
for (( i=1; i<=$pagenum; i++ ))
do
$Cur_Dir/../../../../yii product/search/xundeletenotactiveproduct $nowtime $i
echo "Page $i done"
done
......
#!/bin/sh
Cur_Dir=$(cd `dirname $0`; pwd)
count=`$Cur_Dir/../../../../../yii product/search/synccount`
pagenum=`$Cur_Dir/../../../../../yii product/search/syncpagenum`
###### delete xunsearch
echo "There are $pagenum pages to check if is delete in xunSearch"
echo "##############ALL BEGINING###############";
for (( i=1; i<=$pagenum; i++ ))
do
$Cur_Dir/../../../../../yii product/search/xundeleteallproduct $i
echo "Page $i done"
done
#!/bin/sh
Cur_Dir=$(cd `dirname $0`; pwd)
# init full search collection indexes.
$Cur_Dir/../../../../../yii product/search/initindex
# get now update timestamp.
nowtime=`$Cur_Dir/../../../../../yii product/search/nowtime`
###### 1.Sync Section : Sync Product Serach Collection
# get product all count.
count=`$Cur_Dir/../../../../../yii product/search/synccount`
pagenum=`$Cur_Dir/../../../../../yii product/search/syncpagenum`
echo "There are $count products to process"
echo "There are $pagenum pages to process"
echo "##############ALL BEGINING###############";
for (( i=1; i<=$pagenum; i++ ))
do
$Cur_Dir/../../../../../yii product/search/syncdata $i
echo "Page $i done"
done
# ()delete all search data that sync_updated_at $gt $nowtime.
$Cur_Dir/../../../../../yii product/search/deletenotactiveproduct $nowtime
echo "##############ALL COMPLETE###############";
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册