网上可能有很多教程,我写这个只是记录一下自己学习的过程,给自己看的 。
中文分司网上搜了一下,用的IK分词器(https://github.com/medcl/elasticsearch-analysis-ik),拼音搜索插件用的是拼音分词器(https://github.com/medcl/elasticsearch-analysis-pinyin)。
IK分词器有两种分词模式:ik_max_word和ik_smart模式。
1、ik_max_word
会将文本做最细粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国、中华人民、中华、华人、人民共和国、人民、共和国、大会堂、大会、会堂等词语。
2、ik_smart
会做最粗粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为中华人民共和国、人民大会堂。
安装IK分词器
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.1/elasticsearch-analysis-ik-7.4.1.zip
我的es是7.4所以装了7.4版本
安装拼音分司器
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-pinyin/releases/download/v7.4.1/elasticsearch-analysis-pinyin-7.4.1.zip
按装好分司器后,需在创建索引时指定所用的分词器。以下是PHP的示例代码
/** * 获取创建索引时的分词配置信息 * @param $indexName 索引名称 * @return array */ protected function getIndexSettings($indexName) { return [ 'index' => $indexName, 'body' => [ "settings" => [ "number_of_shards" => 1, "number_of_replicas" => 1, 'analysis' => [ 'analyzer' => [ 'ik_pinyin_analyzer' => [ 'type' => 'custom', 'tokenizer' => 'ik_smart', 'filter' => ['my_pinyin', 'word_delimiter',] ] ], 'filter' => [ 'my_pinyin' => [ 'type' => 'pinyin', 'keep_separate_first_letter' => false, 'keep_full_pinyin' => true, 'keep_original' => false, 'limit_first_letter_length' => 10, 'lowercase' => true, 'remove_duplicated_term' => true ] ] ], ], ], ]; } public function createTestIndex() { $client=$this->getElasticClient(); //取索引的配置信息,创建的索引名称为test $settings = $this->getIndexSettings('test'); //创建索引 $response = $client->indices()->create($settings); return $response; }
创建完索引后再创建映射。
{ "index":"test", "body":{ "news":{ "_source":{ "enabled":true }, "properties":{ "title":{ "type":"text" }, "content":{ "type":"text" }, "author":{ "type":"keyword" } } } } }
上面是创建映射的json(请求体),news是类型名称,网上看了很多,都是这种结构,我反复试了很多次,都没有成功。不知道怎么回事。可能是7.4版本有些不一样吧。最后改成了下面的结构:
{ "index":"test", "body":{ "_source":{ "enabled":true }, "properties":{ "title":{ "type":"text" }, "content":{ "type":"text" }, "author":{ "type":"keyword" } } } }
type:text 表示对该字段做全文索引。(analyzed)
type:keyword 索引这个字段,使之可以被搜索,但是索引内容和指定值一样 (not_analyzed)
php代码如下:
public function createMap() { $client=$this->getElasticClient(); $params = [ 'index' => 'test', 'body' => [ '_source' => [ 'enabled' => true ], 'properties' => [ 'title' => [ 'type' => 'text' ], 'content' => [ 'type' => 'text' ], 'author'=>[ 'type'=>'keyword' ] ] ] ]; $response = $client->indices()->putMapping($params); return $response; }
接下来索引一个文档,看能否用中文和拼音搜索
public function index() { $client = $this->getElasticClient(); $indexName = $this->request->query('index', 'test'); $params = [ 'type' => '_doc', 'index' => $indexName, 'body' => [ 'title' => '英国通过“12月12日提前大选”的议案', 'content' => '当地时间29号晚上大约20:20左右、北京时间大约30日凌晨4:20,英国议会下院表决通过了首相鲍里斯·约翰逊提出的12月12日提前大选的简短议案。由于此前工党决定改变反对提前大选的立场,不出外界所料,约翰逊提出的“12月12日大选”的“一句话”议案在英国议会在英国议会下院以438票支持、20反对的表决结果,顺利获得通过。' ] ]; $response = $client->index($params); return $response; }
测试一下是否可以搜索得到:
POST:/test/_search { "query": { "match": { "title": "英国" } } }
虽然能搜到,并不能说明就是按我设置的中文分司进行的分司。如果是默认的分把每个汉字拆开索引,也可以搜索得到。我又试了一拼音,发现什么也没有搜到。说明我的分词没有起做用。仔细想想,查查文档,发现在创建映射时,可以指定分词,于时删了索引,重建,在建映射时加入分司的设置:
{ "index":"test", "body":{ "_source":{ "enabled":true }, "properties":{ "title":{ "type":"text", "analyzer":"ik_pinyin_analyzer" }, "content":{ "type":"text", "analyzer":"ik_pinyin_analyzer" }, "author":{ "type":"keyword" } } } }
PHP代码如下:
public function createMap() { $client = $this->getElasticClient(); $params = [ 'index' => 'test', 'body' => [ '_source' => [ 'enabled' => true ], 'properties' => [ 'title' => [ 'type' => 'text', "analyzer" => "ik_pinyin_analyzer" ], 'content' => [ 'type' => 'text', "analyzer" => "ik_pinyin_analyzer" ], 'author' => [ 'type' => 'keyword' ] ] ] ]; $response = $client->indices()->putMapping($params); return $response; }
然后索引一段文章,再搜索试一下,发现一切正常,可以用拼音搜索了。