Description
Elasticsearch 是一个分布式数据搜索和存储引擎
本文使用的版本为 Elasticsearch 7.8
导航
简介
Elasticsearch
是一个基于 Apache Lucene
的开源搜索引擎,无论是开源还是专有领域,Lucene
可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库,Lucene
非常复杂,而 Elasticsearch
通过 RESTful API
隐藏了 Lucene
的复杂性,让搜索变得更简单,不过 Elasticsearch
不仅仅是一个搜索,它更是文档型 NoSQL
的一种。
特性
- 分布式的实时文档存储,每个字段都可以被索引并可被搜索
- 分布式的实时分析搜索引擎
- 可以扩展到上百台大集群,处理
PB
级结构化或非结构化数据 - 通过
RESTful API
调用,满足各种编程语言的需求
应用
元数据定义
/**
* 汇报的元数据字段定义
*/
const INDEX_MAPPING_PROPERTIES_WORK_REPORT = [
'work_report_id' => ['type' => 'long'], // 汇报 Id
'user_id' => ['type' => 'long'], // 汇报用户
'to_user_id' => ['type' => 'long'], // 汇报对象
'date' => ['type' => 'date', 'format' => 'yyyy-MM-dd'], // 汇报日期
'last_update_time' => ['type' => 'date', 'format' => 'yyyy-MM-dd HH:mm:ss'], // 最后更新时间
'last_sync_time' => ['type' => 'date', 'format' => 'yyyy-MM-dd HH:mm:ss'], // 数据同步时间
'content' => [ // 汇报内容
'type' => 'text',
'analyzer' => 'ik_max_word', // 索引时的分词模式:会将文本做最细粒度的拆分
'search_analyzer' => 'ik_smart' // 搜索时的分词模式:会做最粗粒度的拆分
],
'username' => [ // 用户名称
'type' => 'text',
'analyzer' => 'username_analyzer',
'search_analyzer' => 'keyword',
],
'project_task_name' => [ // 项目名称
'type' => 'text',
'analyzer' => 'ik_max_word',
'search_analyzer' => 'ik_smart'
],
'work_report' => ['type' => 'keyword']
];
中文人名
检索人名的时候,最好的效果其实就是模糊匹配,以“诸葛亮”为例,通过“诸”、“葛”、“亮”、“诸葛”、“葛亮”、“诸葛亮”都能搜到
Elasticsearch
自带的 standard
分词器在处理中文的时候会直接分割成单字,而中文分词插件 IK
会根据中文语义进行分词,例如“张成功”,会被分成“张”和“成功”,因为“成功”在中文中是一个词语,这两种方式显然都不满足我们的要求
Elasticsearch
自带的 N-gram
分词器可以满足我们的要求,在创建 Index
的时候,设置一个自定义分词器 username_analyzer
,然后将人名字段的分词器设置为 username_analyzer
就可以了
创建 Index
$data = [
'index' => $indexName,
'body' => [
'settings' => [
'index.max_ngram_diff' => 3,
'analysis' => [
'analyzer' => [
'username_analyzer' => [
'tokenizer' => 'username_tokenizer'
]
],
'tokenizer' => [
'username_tokenizer' => [
'type' => 'ngram',
'min_gram' => 1,
'max_gram' => 4,
'token_chars' => []
]
]
]
]
]
];
index.max_ngram_diff
的默认值为 1,max_gram
减去 min_gram
的值不得大于 1,所以这里我们需要一起设置 index.max_ngram_diff
的值为 3,这样就可以处理 4 个字的人名
自定义词库
IK
中文分词插件允许自定义词库,分为两块:自定义字典、自定义停止字典
例如产品名称、项目名称、专用名词等,默认情况下 IK
插件肯定是不能很好的处理的,需要我们通过自定义字典
提供给 IK
而有的词 IK
把它当作一个词语,而你不希望把它当作一个词语,也可以通过自定义停止字典
告诉 'IK'
IK
自定义字典配置文件 [Elasticsearch 目录]/plugins/ik/config/IKAnalyzer.cfg.xml
,格式
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">custom/ext_stopword.dic</entry>
<!--用户可以在这里配置远程扩展字典 -->
<entry key="remote_ext_dict">location</entry>
<!--用户可以在这里配置远程扩展停止词字典-->
<entry key="remote_ext_stopwords">http://xxx.com/xxx.dic</entry>
</properties>
总共 4 项,不需要的可以注释掉
本地的非常简单,在同级目录下有已经有很多的字典文件,是 IK
提供的范本,可以参考新建我们自己的
在实际的应用场景中,肯定是通过接口来实现远程更新更好,远程更新接口需要注意必须包含这么几个 Header
参数 Last-Modified
、 Etag
、 Connection
、 Keep-Alive
、 Content-Length
当字典更新时,要保证 Last-Modified
、 Etag
两个参数至少有一个更新
$wordText = implode(PHP_EOL, $wordArr);
return response($wordText, 200)->header('Content-Type', 'text/plain')
->header('Last-Modified', date('D, d M Y H:i:s e', $lastUpdateTime))
->header('Etag', md5($wordText))
->header('Connection', 'keep-alive')
->header('Keep-Alive', 'timeout=4')
->header('Content-Length', strlen($wordText));
Activity