Yii2 elasticSearch 进行查询

elasticsearch的查询:查询器query 和 过滤器filter

关于查询器query和过滤器filter的区别,可以参看文章:http://www.tuicool.com/articles/7rqAFne

public function getTableTbody()
{
  $pageNum = 3;
  $numPerPage = 50;
  $offset = ($pageNum - 1) * $numPerPage;
  $limit  = $numPerPage ;
  $sort = ['emails' => ['order' => 'desc']];  # emails 按照desc的方式进行排序
  $query = $this->_getSearchQuery();
  $result = $query->orderby($sort)->offset($offset)->limit($limit)->asArray()->all();
  $data = \yii\helpers\BaseArrayHelper::getColumn($result, '_source');
  if(!empty($data))
  {
    foreach($data as $dk => $dr)
    {
    // do something
    }
  }
}

上面使用的_getSearchQuery() 方法如下:

public function _getSearchQuery(){
  # $field_1 $field_2 都是字段
  $filter_arr = [
    'bool' => [
      'must' => [
        ['term' => [$field_1 => 'xxxxxxx']] 
        # $emails_arr 是数组。
        ['terms' => [$field_2 => $emails_arr]]  # 在查询的字段只有一个值的时候,应该使用term而不是terms,在查询字段包含多个的时候才使用terms
      ]
    ],
  ];

  # $field_1 $field_2 都是字段
  $query_arr = [
    'bool' => [
      'must' => [
        ['match' => [$field_1 => 'xxxxx']],
        
      ],
      'should' => [
        # 关于wildcard查询可以参看文章:http://blog.csdn.net/dm_vincent/article/details/42024799
        ['wildcard' => [$field_2 => "W?F*HW"]]
      ]
    ],
  ];

  # Customer 就是elasticSearch 的 model
  $query = Customer::find()->filter($filter_arr)->query($query_arr);
  return $query;
}

对于上面出现的must should,自己查资料,了解elasticSearch

对于term 相当于等于

对于terms相当于mysql中的in

在上述查询中,filter是不分词,不进行同义词查询的,速度肯定要快

query会进行同义词查询的,速度肯定要慢一些的。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Yii2 elasticSearch – Model部分

在上一篇文章,我们配置好了es,那么,我们开始配置model

 

<?php

namespace appadmin\code\Ta\models\elasticSearch;

use yii\elasticsearch\ActiveRecord;

class Customer extends ActiveRecord
{
  public static $currentIndex;
  
  # 定义db链接
  public static function getDb()
  {
    return \Yii::$app->get('elasticsearch');
  }
  
  
  # db
  public static function index()
  {
    return 'ta';
  }
  # table
  public static function type()
  {
    return 'customer';
  }
  
  # 属性
  public function attributes()
    {
        $mapConfig = self::mapConfig();
    return array_keys($mapConfig['properties']);
    }
  # mapping配置
  public static function mapConfig(){
    return [
      'properties' => [
        'customer_id'	=> ['type' => 'long',	"index" => "not_analyzed"],
        'uuids'			=> ['type' => 'string',	"index" => "not_analyzed"],
        'updated_at'	=> ['type' => 'long',	"index" => "not_analyzed"],
        'emails'		=> ['type' => 'string',"index" => "not_analyzed"],
      ]
    ];
  }
  
  public static function mapping()
    {
        return [
            static::type() => self::mapConfig(),
        ];
    }

    /**
     * Set (update) mappings for this model
     */
    public static function updateMapping(){
        $db = self::getDb();
        $command = $db->createCommand();
    if(!$command->indexExists(self::index())){
      $command->createIndex(self::index());
    }
        $command->setMapping(self::index(), self::type(), self::mapping());
    }
  
  public static function getMapping(){
    $db = self::getDb();
        $command = $db->createCommand();
    return $command->getMapping();
  }
  
  
  
}

 

index()方法,可以看成mysql的db

type()可以看成mysql的table,但是实质是有差别的。

mapConfig()是配置mapping,关于elasticSearch的mapping,您可以参看下面的一些资料:

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html

http://blog.csdn.net/lvhong84/article/details/23936697

等等,您可以去搜搜。

由于我不想让elasticSearch 进行分词等操作,我只是想当成一个和数据库类似的搜索,因此,我的mapping的定义为:”index” => “not_analyzed”

当然,index部分,您可以不定义,直接用默认的方式,是会被分词的。mapping类似于一个表定义。

当model建立好,您如果定义了mapping,那么您需要执行一下方法updateMapping(),让es建立mapping,该方法执行一次就可以了。

如果您需要在mapping中添加其他的字段,那么添加后在运行一次updateMapping()

另外需要注意的是:elasticSearch的mapping是不能删除的,建了就是建了,如果要删除,您只能删除index(相当于mysql的db),然后重建mapping,因此,您最好写一个脚本,执行es的所有model的mapping。

到这里,model就讲述完了、

 

Yii2 elasticSearch – 配置部分

配置部分如下:

'elasticsearch' => [
        'class' => 'yii\elasticsearch\Connection',
        'nodes' => [
            ['http_address' => '192.168.0.199:9200'],
            ['http_address' => '192.168.0.210:9200'],
        ],
    ],

您配置了es的集群,那么需要在http_address中把每一个节点的ip都要配置上,

我只有两个节点,那么,我只写了两个IP。

这样就完成了在Yii2中es的配置。

Mongodb 数组型索引报错:WiredTigerIndex::insert: key too large to index, failing

mongodb支持很多种索引,参看官网:https://docs.mongodb.com/manual/indexes/#index-use

创建一个简单索引: db.collection.createIndex({‘name’:1})
这种方式的索引,默认是比较小的,如果值过长就会报错WiredTigerIndex::insert: key too large to index, failing
可以该种hasded的方式 db.collection.createIndex({‘name’:’hashed’}),
如果name是数组格式,而不是字符串,就不能用hashed的索引格式了,这样,我们需要通过另外的方法来解决

https://docs.mongodb.com/manual/reference/parameters/#param.failIndexKeyTooLong

通过设置参数 failIndexKeyTooLong 为false来解决,文档里面有具体的方法,

我的mongodb的启动方式为:

/usr/bin/mongod -f /etc/mongod.conf

我在 /etc/mongod.conf 配置文件中添加下面的配置

setParameter:
  failIndexKeyTooLong: false

关于mongodb的config的详细可以参看地址:

https://docs.mongodb.com/manual/reference/configuration-options/

通过上面的方式,重启mongodb,解决了我的问题,不报错了

 

Yii2 Mongodb 生成递增id的方法

 

代码如下:

public static function increament($tablename){
    
    $coll = Yii::$app->mongodb->getCollection("ids");
    $update = array('?inc'=>array('id'=>1));
    $query = array('name'=>$tablename);
    $command = array(
      'findandmodify'=>'ids', 'update'=>$update,
      'query'=>$query, 'new'=>true, 'upsert'=>true
      );
    
    $result = $coll->mongoCollection->db->command($command);
    $id = $result['value']['id'];
    
    $current_id = (int)$id->value;
    Global $current_id;
    return $current_id;
  }

使用的时候直接 $dd = CID::increament(‘xxx’);即可获取到递增的id,

在一些场景,插入压力不是很多,但是很需要递增id的场景可以使用mongodb的这种递增id的方式,上面的写法是在yii2中使用的写法,如果不在yii2中使用mongodb的递增字段,则可以使用下面的代码:

function increament($m,$database_name,$collection_name){
  
  $ids = "ids";
  $db_name = "tracedb";
  $db = $m->selectDB($db_name);
  //$col = $m->selectDB($db_name)->$ids;
  
  $query = array('name'=>$collection_name);
  $update = array('$inc'=>array('id'=>1));
  $result = $db->command(
            array(
            "findandmodify" => $ids,
            "query" => $query,
            "update" => $update,
            'new'=>true,
            'upsert'=>true
            )
          );

  return $result['value']['id'];
  
  

}

 

Yii2 ElasticSearch aggregate (group) 的例子

直接上代码:

public function actionCountry(){
    $size = 5000;
    $name = 'country_code';
    $type = 'terms';
    $options = [
      'field' => 'country_code',
      'size'  => $size,
    ];
    
    $data = WholeCountryData::find()
        //->limit(5000)
        //->offset(0)
        ->asArray()  
        ->addAgg($name, $type, $options)
        ->createCommand()
        ->search();
    $agg_data = $data['aggregations'];
    $buckets  = $agg_data['country_code']['buckets'];
    //var_dump($agg_data);exit;
    $country_code_arr = \yii\helpers\BaseArrayHelper::getColumn($buckets,'key');
    var_dump($country_code_arr);
    
  }

我想要统计的是country_code 出现的次数,通过yii2的ElasticSearch扩展,上面的例子满足我的需要。

Yii2 elasticSearch 多值查询 和 查询数组字段

Yii2 elasticSearch 多值查询的例子,相当于关系型数据库的in查询

$should = [];
if(is_array($customers) && !empty($customers)){
  foreach($customers as $one){
    $should[] = ['term' => ['customer_id' => $one['customer_id']]];
  }
}
$filter_arr['bool']['should'] = $should;
$result = $obj::find()->filter($filter_arr)
    ->query($query_arr)
    ->asArray()
    ->limit(0)
    ->offset(33)
    ->all();
$data = BaseArrayHelper::getColumn($result, '_source');

查询数组字段,$filter的定义如下:

$filter_arr = [
        'bool' => [
          'must' => [
            ['term' => ['emails' => $email],]
          ]
        ],
      ];

 

 

elasticSearch 批量传递数据,存在数据丢失的原因

elasticSearch 如果字段要做全量匹配,也就是像mysql那样,而不是分词模糊匹配,那么需要建立mapping   加入not_analysised ,这个可以参考之前的文章。

然后我重新传递数据的时候,发现数据存在丢失,最后找出来了原因:

1.如果是多维数组,那么需要建立mapping,不然无法传递数据,但是如果是一维数组,则没有问题,因此,如果是多维数组,可以序列化成字符串存储

2.如果一个字段定义成string,如果长度太长,几千的字符,那么就会保存不了,长度过长,我就是把多维数组序列化后,长度太长无法保存到elasticSearch中,最后,我把多维数组里面的每一个子项进行序列化,然后以一维数组的方式存储,算是解决了这个问题。

elasticSearch在使用的时候,还是有一些坑,需要多练习,多观察一些数据,是否丢失,是否准确等等。

Yii2 – elasticSearch 新建mapping操作

在一些需要完全匹配,或者其他的一些情况,需要建立mapping,这个有点类似mysql的表定义

ActiveRecord的定义:

<?php

namespace appadmin\code\Ta\models\elasticSearch;

use yii\elasticsearch\ActiveRecord;

class TraceData extends ActiveRecord
{
  public static $currentIndex;
  
  # 定义db链接
  public static function getDb()
  {
    return \Yii::$app->get('elasticsearch_TA');
  }
  
  # 不同的website 使用的是不同的db ,使用前需要先初始化
  # db的名字
  public static function initDb($website_id){
    if($website_id){
      self::$currentIndex = 'ta'."_".$website_id;
    }
  }
  
  
  
  # db
  public static function index()
  {
    return self::$currentIndex;
  }
  # table
  public static function type()
  {
    return 'trace_data';
  }
  
   public function attributes()
    {
        $mapConfig = self::mapConfig();
    return array_keys($mapConfig['properties']);
    }
  
  public static function mapConfig(){
    return [
      'properties' => [
        'id'				=> ['type' => 'string',"index" => "not_analyzed"],
        'ip'				=> ['type' => 'string',"index" => "not_analyzed"],
        'service_date_str'	=> ['type' => 'string',"index" => "not_analyzed"],
        'service_datetime'	=> ['type' => 'string',"index" => "not_analyzed"],
        'service_timestamp'	=> ['type' => 'integer',"index" => "not_analyzed"],
        'devide' 			=> ['type' => 'string',"index" => "not_analyzed"],
        'user_agent' 		=> ['type' => 'string',"index" => "not_analyzed"],
        'browser_name' 		=> ['type' => 'string',"index" => "not_analyzed"],
        'browser_version'	=> ['type' => 'string',"index" => "not_analyzed"],
        'browser_date'		=> ['type' => 'string',"index" => "not_analyzed"],
        'browser_lang'		=> ['type' => 'string',"index" => "not_analyzed"],
        'operate' 			=> ['type' => 'string',"index" => "not_analyzed"],
        'operate_relase'	=> ['type' => 'string',"index" => "not_analyzed"],
        'domain' 			=> ['type' => 'string',"index" => "not_analyzed"],
        'url'				=> ['type' => 'string',"index" => "not_analyzed"],
        'title'				=> ['type' => 'string',"index" => "not_analyzed"],
        'refer_url'			=> ['type' => 'string',"index" => "not_analyzed"],
        'first_referrer_domain'	=> ['type' => 'string',"index" => "not_analyzed"],
        'is_return'			=> ['type' => 'integer',"index" => "not_analyzed"],
        'uuid'				=> ['type' => 'string',"index" => "not_analyzed"],
        'device_pixel_ratio'=> ['type' => 'string',"index" => "not_analyzed"],
        'resolution'		=> ['type' => 'string',"index" => "not_analyzed"],
        'color_depth'		=> ['type' => 'string',"index" => "not_analyzed"],
        'website_id'		=> ['type' => 'integer',"index" => "not_analyzed"],
        'sku'				=> ['type' => 'string',"index" => "not_analyzed"],
        'country_code'		=> ['type' => 'string',"index" => "not_analyzed"],
        'country_name'		=> ['type' => 'string',"index" => "not_analyzed"],
        
        'order_status' 		=> ['type' => 'string',"index" => "not_analyzed"],
        'cart' 				=> ['type' => 'string',"index" => "not_analyzed"],
        'order'				=> ['type' => 'string',"index" => "not_analyzed"],
        'category'			=> ['type' => 'string',"index" => "not_analyzed"],
        'login_email'		=> ['type' => 'string',"index" => "not_analyzed"],
        'register_email'	=> ['type' => 'string',"index" => "not_analyzed"],
        'search'			=> ['type' => 'string',"index" => "not_analyzed"],
        'currency'			=> ['type' => 'string',"index" => "not_analyzed"],
        'url_new'			=> ['type' => 'string',"index" => "not_analyzed"],
        'stay_seconds'		=> ['type' => 'integer',"index" => "not_analyzed"],
        'first_visit_this_url'	=> ['type' => 'string',"index" => "not_analyzed"],
      ]
    ];
  }
  
  public static function mapping()
    {
        return [
            static::type() => self::mapConfig(),
        ];
    }

    /**
     * Set (update) mappings for this model
     */
    public static function updateMapping(){
        $db = self::getDb();
        $command = $db->createCommand();
    if(!$command->indexExists(self::index())){
      $command->createIndex(self::index());
    }
        $command->setMapping(self::index(), self::type(), self::mapping());
    }
  
  public static function getMapping(){
    $db = self::getDb();
        $command = $db->createCommand();
    return $command->getMapping();
  }
  
  
  
}

使用:

public function actionMapping($websiteIds){
    $arr = explode(",",$websiteIds);
    foreach($arr as $website_id){
      TraceData::initDb($website_id);
      TraceData::updateMapping();
      $map = TraceData::getMapping();
      var_dump($map);
    }
}

通过updateMapping来更新mapping

通过getMapping得到定义好的mapping

在这里的一个坑就是:在添加表(type)mapping的时候,需要提前定义Index(相当于mysql的db),才能添加type(相当于表),否则添加不上,或者报错。

其他资料:
https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html

http://www.open-open.com/lib/view/open1455452874636.html

Yii2 – 批量插入数据到 elasticSearch

elasticSearch 是目前来说,最强大的开源搜索引擎,对于一些搜索,放到ElasticSearch中,速度会快很多,当然,这个玩意也是非常消耗资源。

下面是,使用yii2,将数据批量导入到ES中,单行插入的效率太低,使用批量插入,速度还是可以。

安装ElasticSearch 这个参看

安装ElasticSearch ,以及在yii2中的使用

2. 安装yii2-ElasticSearch插件

https://github.com/yiisoft/yii2-elasticsearch

3. 配置

'elasticsearch_TA' => [
    'class' => 'yii\elasticsearch\Connection',
    'nodes' => [
        ['http_address' => '192.168.0.199:9200'],
        ['http_address' => '192.168.0.210:9200'],
    ],
],

4.使用

传递数据,我们还是用shell 脚本来传递数据 /appta/shell/customer/syncCustomerDataToEs.sh

#!/bin/sh

DIR=$(cd `dirname $0`; pwd)
# sync mongodb to elasticsearch
echo 'sync custom data to es'
processDate=$1
websiteIds=$2

arr=$(echo $websiteIds|tr "," "\n");
for website_id in $arr; do
  echo "website_id:".$website_id;
  variable=`$DIR/../../../yii ta/migrate/elasticsearch/customerdatapagecount $processDate $website_id`
  echo "$variable.."
  for (( i=1; i<=$variable; i++ ))
  do 
    $DIR/../../../yii ta/migrate/elasticsearch/customerdata $processDate $website_id $i 
    echo "Page $i done"
  done
done







controller文件:

<?php
namespace appadmin\code\Ta\console\migrate;
use Yii;
use appadmin\code\Ta\models\WebsiteBaseInfo;
use yii\console\Controller;
use appadmin\code\Ta\helper\mongoDb as MongoDb;
use appadmin\code\Ta\models\mongo\CustomerData as MgCustomerData;
use appadmin\code\Ta\models\elasticSearch\CustomerData as EsCustomerData;

use appadmin\code\Ta\models\mongo\TraceData as MgTraceData;
use appadmin\code\Ta\models\elasticSearch\TraceData as EsTraceData;


class ElasticsearchController extends Controller
{
  public $numPerPage = 1000;
  //public $dbName = "ta_".$processDate;
  //public $collName;
  
  public function initParam($processDate,$website_id){
    //$thidbName = "ta_".$processDate;
    $collName = "ta_".$website_id."_customer_data";
    //echo $processDate;exit;
    MongoDb::setDbByDate($processDate);
    MgCustomerData::initCollName($website_id);
    MgTraceData::initCollName($website_id);
  }
  # customer data  数据的总页数
  public function actionCustomerdatapagecount($processDate,$website_id){
    $this->initParam($processDate,$website_id);
    $count =  MgCustomerData::find()->count();
    //var_dump(MgCustomerData::getDb());
    //echo $count;exit;
    echo ceil($count/$this->numPerPage);
  }
  # 同步customer data的数据到ElasticSearch
  public function actionCustomerdata($processDate,$website_id,$pageNum){
    $this->initParam($processDate,$website_id);
    $skip = $this->numPerPage * ($pageNum - 1);
    $data = MgCustomerData::find()
        ->asArray()
        ->limit($this->numPerPage)
        ->offset($skip)
        ->all();
    $arr = [];
    $i = 0;
        
    if(is_array($data) && !empty($data )){
      $elasticsearch = Yii::$app->elasticsearch_TA;
      $bulkclient = $elasticsearch->createBulkCommand();
      //EsCustomerData::initDb($website_id);
      $index_name = 'ta_'.$website_id;
      $one_day_type = 'customer_data';
      //$EsCustomerDataOne = EsCustomerData::findOne($a['_id']);
      foreach($data  as $one){
        $i++;
        $a = [];
        $a['id'] = $one['_id'];
        $value = $one['value'];
        if(is_array($value) && !empty($value )){
          foreach($value  as $k => $v){
            if($k == 'data'){
              //var_dump($v);
              $v = serialize($v);
            }
            $a[$k] = $v;
          }
        }
        
        $bulkclient->addAction(array(
          'index' => array(
            '_index'=> $index_name,
            '_type' => $one_day_type,
            '_id' 	=> $one['_id'],
          )
        ), $a);
        /*
        # 保存数据到ES
        EsCustomerData::initDb($website_id);
        $EsCustomerDataOne = EsCustomerData::findOne($a['_id']);
        if(!$EsCustomerDataOne){
          $EsCustomerDataOne = new EsCustomerData;
          $EsCustomerDataOne->setPrimaryKey($a['_id']);
        }
        $EsCustomerDataOne->id = $a['_id'];
        $attributes = $EsCustomerDataOne->attributes();
        foreach($a as $k=>$v){
          if(in_array($k,$attributes)){
            if($k == 'data'){
              //var_dump($v);
              $v = serialize($v);
            }
            $EsCustomerDataOne[$k] = $v;
          }
        }
        $mtime=explode(' ',microtime());
        $startTime=$mtime[1]+$mtime[0];        
        
        $EsCustomerDataOne->save();
        $mtime=explode(' ',microtime());
        $endTime=$mtime[1]+$mtime[0];        
        echo "chaju_time :($i)".($endTime-$startTime)."\n"; 
        //$arr[] = $a; 
        */
      }
      $bulkclient->execute();
    }
    
    
  }
    
  # customer data  数据的总页数
  public function actionTracedatapagecount($processDate,$website_id){
    $this->initParam($processDate,$website_id);
    $count =  MgTraceData::find()->count();
    //var_dump(MgCustomerData::getDb());
    //echo $count;exit;
    echo ceil($count/$this->numPerPage);
  }
  # 同步customer data的数据到ElasticSearch
  public function actionTracedata($processDate,$website_id,$pageNum){
    $this->initParam($processDate,$website_id);
    $skip = $this->numPerPage * ($pageNum - 1);
    $data = MgTraceData::find()
        ->asArray()
        ->limit($this->numPerPage)
        ->offset($skip)
        ->all();
    $arr = [];
    $i = 0;
        
    if(is_array($data) && !empty($data )){
      $elasticsearch = Yii::$app->elasticsearch_TA;
      $bulkclient = $elasticsearch->createBulkCommand();
      //EsCustomerData::initDb($website_id);
      $index_name = 'ta_'.$website_id;
      $one_day_type = 'trace_data';
      //$EsCustomerDataOne = EsCustomerData::findOne($a['_id']);
      foreach($data  as $one){
        $i++;
        $a = [];
        
        if(is_array($one) && !empty($one )){
          foreach($one  as $k => $v){
            $a[$k] = $v;
          }
        }
        $a['id'] = $a['_id'];
        unset($a['_id']);
        
        $bulkclient->addAction(array(
          'index' => array(
            '_index'=> $index_name,
            '_type' => $one_day_type,
            '_id' 	=> $one['_id'],
          )
        ), $a);
        
      }
      $bulkclient->execute();
    }
    
    
  }	
    
    
    
    
    
    
    
    
    
    
    
}

appadmin\code\Ta\models\mongo\CustomerData

<?php  
# 商家SELLER 和  对应的 SELLERID 的设置。 
namespace appadmin\code\Ta\models\mongo; 
use yii\mongodb\ActiveRecord;
use fec\helpers\CDate;
use fec\helpers\CConfig;
use Yii;
use appadmin\code\Ta\helper\mongoDb;
# use appadmin\code\Ta\models\mongo\CustomerData; 
class CustomerData extends ActiveRecord  
{  
  
  public static $_collectionName;
  
  # 定义db
  public static function getDb()
    {
    return \Yii::$app->get('mongodb_ta_date');
    }
  
  
  
  # 定义collection name  
    public static function collectionName()  
    {  
        return self::$_collectionName;  
    }  
  
  
  
  
  public static function initCollName($website_id){
    self::$_collectionName = "ta_".$website_id."_customer_data";
  }
  
  
  public function attributes()
    {
        // path mapping for '_id' is setup to field 'id'
        return [
      '_id', 
      'value',
      
    ];
    }
  
  
}  

appadmin\code\Ta\models\ElasticSearch\CustomerData

<?php

namespace appadmin\code\Ta\models\elasticSearch;

use yii\elasticsearch\ActiveRecord;

class CustomerData extends ActiveRecord
{
  public static $currentIndex;
  
  # 定义db链接
  public static function getDb()
  {
    return \Yii::$app->get('elasticsearch_TA');
  }
  
  # 不同的website 使用的是不同的db ,使用前需要先初始化
  # db的名字
  public static function initDb($website_id){
    //echo 888;
    if($website_id){
      //echo 999;
      self::$currentIndex = 'ta'."_".$website_id;
      //echo self::$currentIndex;
      //echo 3;
    }
  }
  
  
  
  # db
  public static function index()
  {
    return self::$currentIndex;
  }
  # table
  public static function type()
  {
    return 'customer_data';
  }
  
   public function attributes()
    {
        // path mapping for '_id' is setup to field 'id'
        return [
      'id',
      
      'uuid',
      'customer_id',
      'pv',
      
      'ip',
      'service_date_str',
      'service_datetime',
      'service_timestamp',
      'devide',
      'user_agent',
      'browser_name',
      'browser_version',
      'browser_date',
      'browser_lang',
      'operate',
      'operate_relase',
      'domain',
      'url',
      'title',
      'refer_url',
      'first_referrer_domain',
      'is_return',
      'uuid',
      'device_pixel_ratio',
      'resolution',
      'color_depth',
      'website_id',
      'sku',
      'country_code',
      'country_name',
      
      'data',
      
      'order_status',
      'cart',
      'order',
      'category',
      'login_email',
      'register_email',
      'search',
      'currency',
      'stay_seconds',
    ];
    }
  
  
  
}