Yii2 elasticSearch 多值查询 和 查询数组字段
代码如下:$data 是一个数组。
if(is_array($data) && !empty($data )){
$elasticsearch = Yii::$app->elasticsearch;
$bulkclient = $elasticsearch->createBulkCommand();
# elasticSearch的index,相当于mysql的数据库
$index_name = 'fecshop';
# elasticSearch的type,相当于mysql的table
$type_name = 'whole_free_sku_data';
echo $index_name."###".$type_name." \n";
foreach($data as $one){
$i++;
$a = [];
$a['sku_id'] = $one['_id'];
$value = $one['value'];
# 将多维数组部分进行序列化。
if(is_array($value) && !empty($value )){
foreach($value as $k => $v){
if(in_array($k,['devide','country_code','browser_name','operate'])){
if(is_array($v) && !empty($v)){
$vv = [];
foreach($v as $vk => $o){
$vv[] = serialize([$vk=>$o]);
}
$v = $vv;
}
}
$a[$k] = $v;
}
}
# 去掉_id字段。
unset($a['_id']);
$bulkclient->addAction(array(
'index' => array(
'_index'=> $index_name,
'_type' => $type_name,
'_id' => $one['_id'],
)
), $a);
}
$bulkclient->execute();
}
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会进行同义词查询的,速度肯定要慢一些的。
在上一篇文章,我们配置好了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就讲述完了、
配置部分如下:
'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的配置。
在命令行输入如下命令,即可查看镜像地址:
$ composer config -g repo.packagist
{"type":"composer","url":"https://packagist.org","allow_ssl_downgrade":true}
也可以使用 composer config -l -g 查看所有全局配置
下面有把地址修改为中国镜像,如果中国镜像出现了问题,那么您可以还原成官方的默认地址,下面是详细。
启用中国全量镜像服务有两种方式,具体配置方法如下:
即将配置信息添加到 Composer 的全局配置文件 config.json 中。修改composer的全局配置文件(推荐方式),打开命令行并执行如下命令:
默认地址改为中国镜像地址:
composer config -g repo.packagist composer https://packagist.phpcomposer.com
中国镜像地址还原成默认地址:(注意:这个是将中国镜像还原)
composer config -g repo.packagist composer https://packagist.org
即将将配置信息添加到某个项目的 composer.json 文件中。修改当前项目的composer.json配置文件有两种方式,最后都是向文件中添加如下配置信息:
"repositories": {
"packagist": {
"type": "composer",
"url": "https://packagist.phpcomposer.com"
}
}
2.1 打开命令行并进入项目的根目录(也就是 composer.json 文件所在目录),执行如下命令:
默认地址改为中国镜像地址:
composer config repo.packagist composer https://packagist.phpcomposer.com
该命令将会在当前项目中的 composer.json 文件的末尾自动添加镜像的配置信息
中国镜像地址还原成默认地址:(注意:这个是将中国镜像还原)
composer config repo.packagist composer https://packagist.org
2.2 手动向composer.json文件中添加以上信息
默认地址改为中国镜像地址:
"repositories": {
"packagist": {
"type": "composer",
"url": "https://packagist.phpcomposer.com"
}
}
中国镜像地址还原成默认地址:(注意:这个是将中国镜像还原)
将url的值改为:https://packagist.org
在yii2中,我们通过下面的方法,将controller的数组传递给view
public function actionIndex()
{
$data = ['xx' => 'yy'];
return $this->render($this->action->id,$data);
}
在view文件中就可以使用$xx变量了,这个变量的值是’yy’.
现在我们想给layout里面传递,怎么办呢?下面是原理:
在yii/base/Controller.php中可以看到如下代码:
public function render($view, $params = [])
{
$content = $this->getView()->render($view, $params, $this);
return $this->renderContent($content);
}
查找renderContent()方法
public function renderContent($content)
{
$layoutFile = $this->findLayoutFile($this->getView());
if ($layoutFile !== false) {
return $this->getView()->renderFile($layoutFile, ['content' => $content], $this);
}
return $content;
}
可以看到,我们只要重写renderContent()方法,在这个方法的内容部分:
[‘content’ => $content]
在这个数组中,添加上我们的想要的其他的数组,譬如:
[‘content’ => $content, ‘tt’ => ‘terry’]
我们就可以在layout里面使用$tt变量了。也就是将controller中的变量传递给layout。
在网站加载的时候,为了快速,浏览器一般会缓存js和css,但是,我们网站如果更新了css和js,怎么告诉浏览器呢、?我么可以通过js和css url的参数方式来解决。
譬如:
/assets/dbdba3fa/js/js.js?v=2
在fecshop中,可以通过参数配置的方式,全部更改js和css的版本号。
如果我们更改了js,那么我们修改为
/assets/dbdba3fa/js/js.js?v=3
,由于是不同的链接,浏览器本地没有这个链接的内容,自然就会去服务器获取这个js的内容。
这也就是为什么我们看到很多网站的css和js后面带这个奇怪的v参数的原因。
在很多网站,我们会发现这么一个问题,为什么很多网站的image js css 和网站的域名不一样呢?
譬如网站是www.fecshop.com , 但是图片地址为image1.tomtop.com
css和js的地址为xxx.fecshop.com,为什么要这样搞呢?
下面细说一下原因,原因有两点:
1.浏览器在并发加载网站链接内容的时候,每一个域名的并发加载url都有一定的数量限制,如果用不同的域名,那么一次性加载的url就会变多,这样可以快速渲染加载页面。
2.网站一般都是有状态的,也就是有cookie和session等,无论什么链接,都要发送cookie的,譬如网站是www.fecshop.com,那么www.fecshop.com/logo.jpg也是会发送cookie的,包括js和css文件,都会发送cookie,这就带来无意义的发送,增加额外开销,因此,对于图片js,css等,我们使用不同的域名,就不会发送cookie了。
上面是我想到的两点,如果有其他的观点,欢迎拍砖。
当然, 也有的是为了CDN的考虑,用不同的域名解析都CDN服务器上面。
yum install -y enca
在文件夹根目录下面创建文件:iconv_shell.sh
里面填写下面的内容:
#!/bin/bash for file in `find ./ -name '*.php'`; do echo "$file" # iconv -f gb2312 -t utf8 -o $file $file enca -L zh_CN -x UTF-8 $file done
执行:
sh iconv_shell.sh