[
](https://lccdn.phphub.org/uploads/images/201804/19/10512/Ncx25uq2lR.png?imageView2/2/w/1240/h/0)
最近公司项目要使用全文搜索引擎,之前使用过的sphInx
,似乎没有那么好用了,而且中文分词也没有合适的 ,所以准备换个其它的来试试,老项目使用的是thinkphp 3.1
框架,虽然框架老了点。但是新的想法还是可以用上的,这里只是简单演示下elasticsearch
的上手体难,实际项目中还需要完善。
因本文环境为 Laradock
,所以直接使用 elasticsearch
的镜像即可,这里省略了 java
环境的安装及 elasticsearch
软件的安装,网上教程很多,请自行查找,后期会补上一个,这里默认已经安装好了。
浏览器打开 http://localhost:9200/ 或者终端执行
curl 'http://localhost:9200/?pretty'
你会看到如下响应
{
name: "g2ODObY",
cluster_name: "laradock-cluster",
cluster_uuid: "w8Hhov2bQDi_Wo2DEx044Q",
version: {
number: "6.2.3",
build_hash: "c59ff00",
build_date: "2018-03-13T10:06:29.741383Z",
build_snapshot: false,
lucene_version: "7.2.1",
minimum_wire_compatibility_version: "5.6.0",
minimum_index_compatibility_version: "5.0.0"
},
tagline: "You Know, for Search"
}
如果响应正常显示,说明你安装成功了。
这里需注意一点,查看elasticsearch
配置:vi config/elasticsearch.yml
network.host: 0.0.0.0 //这里默认不绑定,但安全起见,在实际项目中,请绑定本机 IP。
这里使用的是 analysis-ik
中文插件,项目地址,需根据不同的 Elasticsearch
版本选择插本版本,本项目使用的最新的 6.2.3 版本。
进入 elasticsearch
目录
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.2.3/elasticsearch-analysis-ik-6.2.3.zip
查看是否安装成功(注意你的 elasticsearch 版本,版本不同命令不同)
./bin/elasticsearch-plugin list
返回结果
analysis-ik
ingest-geoip
ingest-user-agent
...
看到 analysis-ik
证明你插件安装成功了,你也可以到 plugins
目录下查看插件是否存在
$ cd plugins
drwxr-xr-x 2 root root 4096 Apr 17 03:08 analysis-ik
drwxrwxr-x 2 elasticsearch root 4096 Mar 13 11:35 ingest-geoip
drwxrwxr-x 2 elasticsearch root 4096 Mar 13 11:35 ingest-user-agent
drwxrwxr-x 11 elasticsearch root 4096 Mar 13 11:35 x-pack
Thinkphp
没有 laravel
那么方便,但是用个 trait
还是可以的。
新建一个traits
<?php
use Elasticsearch\ClientBuilder;
trait Elastic
{
private $client;
public function __construct()
{
$hosts=[
env('ELASTICSEARCH_URL','localhost:9200')
];
$this->client = ClientBuilder::create()
->setHosts($hosts) //因 docker的特殊性,这里需指定 IP 地址,env 文件中配置
->build();
}
}
laravel
的 env
实现其它是用的 vlucas/phpdotenv
,所以我在 Thinkphp
中也把他拿了过来。
这里首先实例化一个 client
。
$params = [
'index' => $index,//索引名(相当于mysql的数据库)
'body' => [
'settings' => [
'number_of_shards' => 1, //一个索引中含有的主分片的数量
'number_of_replicas' => 0 //每一个主分片关联的副本分片的数量
],
'mappings' => [
$type => [ //类型名(相当于mysql的表)
'_all'=>[ // 是否开启所有字段的检索
'enabled' => 'false'
],
'_source' => [ // 存储原始文档
'enabled' => true
],
'properties' => [ //文档类型设置(相当于mysql的数据类型)
'id' => [
'type' => 'integer', // //类型 string、integer、float、double、boolean、date,text,keyword
//'index'=> 'not_analyzed',//索引是否精确值 analyzed not_analyzed
],
'title' => [
'type' => 'text', // 字段类型为全文检索,如果需要关键字,则修改为keyword,注意keyword字段为整体查询,不能作为模糊搜索
"analyzer"=> "ik_max_word",
"search_analyzer"=> "ik_max_word",
],
'body' => [
'type' => 'text',
"analyzer"=> "ik_max_word",
"search_analyzer"=> "ik_max_word",
]
]
]
]
]
];
return $this->client->indices()->create($params);
这里需要注意的是 analyzer
, IK
插件目前只支持两种: ik_max_word
和ik_smart
,
ik_max_word
: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合;ik_smart
: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。
返回如下信息说明创建成功
array:3 [▼
"acknowledged" => true
"shards_acknowledged" => true
"index" => "my_index"
]
这里使用的 dd
打印的结果,之后的结果承现一样用 dd
打印。
$params = [
'index' => 'my_index',
];
return $this->client->indices()->delete($params);//删除索引设置
返回如下
array:1 [▼
"acknowledged" => true
]
// 查看一个索引的设置
$params = ['index' => 'my_index'];
$response = $client->indices()->getSettings($params);
// 查看多少索引的设置
$params = [
'index' => [ 'my_index', 'my_index2' ]
];
$response = $client->indices()->getSettings($params);
返回信息如下
array:1 [▼
"my_index" => array:1 [▼
"settings" => array:1 [▼
"index" => array:6 [▼
"creation_date" => "1524037463950"
"number_of_shards" => "1"
"number_of_replicas" => "0"
"uuid" => "okYiWK0WRiqebMAHUCsvzA"
"version" => array:1 [▼
"created" => "6020399"
]
"provided_name" => "my_index"
]
]
]
]
mapping
信息//获取所有索引和类型的 mapping 信息
$response = $client->indices()->getMapping();
//获取 my_index 索引的所有类型的 mapping
$params = ['index' => 'my_index'];
$response = $client->indices()->getMapping($params);
//获取所有类型为 my_type 的 mapping信息,不管索引是什么
$params = ['type' => 'my_type' ];
$response = $client->indices()->getMapping($params);
//获取 my_index 索引 下 my_type 类型的 mapping 信息
$params = [
'index' => 'my_index'
'type' => 'my_type'
];
$response = $client->indices()->getMapping($params);
//获取多个索引的 mapping 信息
$params = [
'index' => [ 'my_index', 'my_index2' ]
];
$response = $client->indices()->getMapping($params);
返回如下代码
array:1 [▼
"my_index" => array:1 [▼
"mappings" => array:1 [▼
"my_type" => array:2 [▼
"_all" => array:1 [▼
"enabled" => false
]
"properties" => array:3 [▼
"body" => array:2 [▼
"type" => "text"
"analyzer" => "ik_max_word"
]
"id" => array:1 [▼
"type" => "integer"
]
"title" => array:2 [▼
"type" => "text"
"analyzer" => "ik_max_word"
]
]
]
]
]
]
1.增加单条数据
$data=[
'title' => '我爱北京天安门',
'body' => '天安门上太阳升'
];
$params = [
'index' => 'my_index',
'type' => 'my_type',
// 'id' => 'my_id', // 不填则会自动生成唯一的id
'body' => $data
];
return $this->client->index($params);
返回如下
array:8 [▼
"_index" => "my_index"
"_type" => "my_type"
"_id" => "WKXd12IBwuLBOSSKe5k_" //当前数据的唯一id
"_version" => 1
"result" => "created"
"_shards" => array:3 [▼
"total" => 2
"successful" => 1
"failed" => 0
]
"_seq_no" => 0
"_primary_term" => 1
]
2.批量增加多条数据
$dataList =[
[
'id' => '10001',
'title' => '北京',
'body' => '我们是首都',
],[
'id' => '10002',
'title' => '上海',
'body' => '啊啦是上海人',
],[
'id' => '10003',
'title' => '广州',
'body' => '我们有小蛮腰',
],[
'id' => '10004',
'title' => '深圳',
'body' => '我们啥也没有,来了就是深圳人。',
],
];
foreach($dataList as $value){
$params['body'][] = [
'index' => [
'_index' => 'my_index',
'_type' => 'my_type',
'_id' =>$value['id']
]
];
$params['body'][] = [
'id' => $value['id'],
'title' => $value['title'],
'body' => $value['body'],
];
}
return $this->client->bulk($params);
这里需注意,批量增加多条数据时并不是直接将数组扔进去,而是要进行处理,生成对应的数组后使用 bulk
方法批量创建。
返回如下
array:3 [▼
"took" => 27
"errors" => false
"items" => array:4 [▼
0 => array:1 [▼
"index" => array:9 [▼
"_index" => "my_index"
"_type" => "my_type"
"_id" => "10001"
"_version" => 1
"result" => "created"
"_shards" => array:3 [▼
"total" => 2
"successful" => 1
"failed" => 0
]
"_seq_no" => 1
"_primary_term" => 1
"status" => 201
]
]
1 => array:1 [▼
"index" => array:9 [▼
"_index" => "my_index"
"_type" => "my_type"
"_id" => "10002"
"_version" => 1
"result" => "created"
"_shards" => array:3 [▼
"total" => 2
"successful" => 1
"failed" => 0
]
"_seq_no" => 2
"_primary_term" => 1
"status" => 201
]
]
...
这里使用了 $dataList
自带的 id
,在实际项目中建议使用数据的 id
,用做数据的唯一 id
,方便通过 id
查询数据。
删除文档只能单条删除,需指定数据 ID
$param = [
'index' => 'my_index',
'type' => 'my_type',
'id' => 'my_id' // 指定数据ID
];
return $this->client->delete($param);
返回如下
array:1 [▼
"acknowledged" => true
]
查询数据需指定数据 ID
$params = [
'index' => 'my_index',
'type' => 'my_type',
'id' => 'WKXd12IBwuLBOSSKe5k_' // 此 ID 为自动生成的 ID,项目中建议查询手动录入ID
];
return $this->client->get($params);
返回如下
array:6 [▼
"_index" => "my_index"
"_type" => "my_type"
"_id" => "WKXd12IBwuLBOSSKe5k_"
"_version" => 1
"found" => true
"_source" => array:2 [▼
"title" => "我爱北京天安门"
"body" => "天安门上太阳升"
]
]
$params = [
'index' => 'my_index',
'type' => 'my_type',
'id' => 'WKXd12IBwuLBOSSKe5k_',//指定 id, 这里为之前录入时自动生成的 id
'body' => [
'doc' => [ // 必须带上doc.表示是数据操作
'age' => 150
]
]
];
return $this->client->update($params);
返回如下
array:8 [▼
"_index" => "my_index"
"_type" => "my_type"
"_id" => "WKXd12IBwuLBOSSKe5k_"
"_version" => 2
"result" => "updated"
"_shards" => array:3 [▼
"total" => 2
"successful" => 1
"failed" => 0
]
"_seq_no" => 4
"_primary_term" => 1
]
再次查询数据
array:6 [▼
"_index" => "my_index"
"_type" => "my_type"
"_id" => "WKXd12IBwuLBOSSKe5k_"
"_version" => 2
"found" => true
"_source" => array:3 [▼
"title" => "我爱北京天安门"
"body" => "天安门上太阳升"
"age" => 150
]
]
发现返回数据中多了 age
字段, 修改成功。
先来个简单的.
$params = [
'index' => 'my_index', //['my_index1', 'my_index2'],可以通过这种形式进行跨库查询
'type' => 'my_type', //['my_type1', 'my_type2'],
'body' => [
'query'=>[
'match'=>[
"title" => '北京',
],
],
]
];
return $this->client->search($params);
返回如下
array:4 [▼
"took" => 188
"timed_out" => false
"_shards" => array:4 [▼
"total" => 5
"successful" => 5
"skipped" => 0
"failed" => 0
]
"hits" => array:3 [▼
"total" => 2
"max_score" => 1.6451461
"hits" => array:2 [▼
0 => array:5 [▼
"_index" => "my_index"
"_type" => "my_type"
"_id" => "10001"
"_score" => 1.6451461
"_source" => array:3 [▼
"id" => "10001"
"title" => "北京"
"body" => "我们是首都"
]
]
1 => array:5 [▼
"_index" => "my_index"
"_type" => "my_type"
"_id" => "WKXd12IBwuLBOSSKe5k_"
"_score" => 0.94175816
"_source" => array:3 [▼
"title" => "我爱北京天安门"
"body" => "天安门上太阳升"
"age" => 150
]
]
]
]
]
可以看到,title
中包含北京
的数据已经全部返回了。
Elasticsearch
最重要的也是最灵活的就是搜索了,你能想到的方法基本上Elasticsearch
都已经帮你做好,比如: term
,match
,multi_match
,range
.prefix
,wildcard
,regexp
.fuzzy
,match_phrase
,match_phrase_prefix
,exists
等等,了解具体方法的使用请参考:
原文地址:http://www.qiehe.net/posts/4/the-use-and-configuration-of-elasticsearch-for-full-text-search
Good Good Study , Day Day Up!!
Original url: Access
Created at: 2018-10-10 17:27:33
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论