目录
1.全文搜索Lucene 的基础认识
1.1 概念
Lucene主要针对文本数据的搜索。数据可分为:“结构化”数据(关系数据库表形式管理的数据),半结构化数据(XML文档、JSON文档),和非结构化数据(WORD、PDF),通常而言在结构化的数据中搜索性能是比较高的,全文搜索的目的就是把非结构化的数据变成结构化的数据再进行搜索,从而提高搜索效率。Lucene是apache下的一个开源的全文检索引擎工具包(一堆jar包)。它为软件开发人员提供一个简单易用的工具包(类库),以方便的在小型目标系统中实现全文检索的功能。
1.2 优点
(1)搜索效率高,是模糊查询无法比拟的;
(2)能够跟据关键字与内容关联性的高低进行排序;
(3)以单词方式进行搜索,查询所有包含该条件的数据。
1.3 Lucene索引原理
Lucene索引其实就是将现实世界中所有的结构化和非结构化数据提取的信息通过索引来查询对应的信息。因为当你创建Lucene索引时就会将这些数据进行分词,将每一个单词对应一个编号,一一对应。并且由于在搜索的过程中,由于对于搜索的过程中大写和小写指的都是同一个单词,在这就没有区分的必要,所有按规则统一变为小写。而为了要加快搜索速度,就得必须保证这些单词的排列时有一定规律,于是按单词的字母规律来进行排列,最后再简化索引,合并相同的单词,就得到了倒排索引文档。
2.ElasticSearch和Kinban的安装
2.1 ElasticSearch安装
2.1.1 下载ElasticSearch
ES服务只依赖于JDK,推荐使用JDK1.8+
下载地址:Download Elasticsearch | Elastic
2.1.2 安装与启动
解压即可,双击安装目录 bin/elasticsearch.bat即可启动
2.1.3 ElasticSearch测试
使用浏览器访问:http://localhost:9200或者 http://127.0.0.1:9200
看到上图信息,恭喜你,你的ES集群已经启动并且正常运行.
2.1.4 ES内存配置
如果ES启动占用的内存比较大可以通过修改 jvm.options 文件来修改内存,该文件路径D:\ES\elasticsearch-6.8.6\config,也就是你解压后的文件的config目录下。
2.2 Kibana5安装
2.2.1 下载Kibana5
下载地址:Download Kibana Free | Get Started Now | Elastic
2.2.2 安装与启动
解压即可安装 , 执行bin\kibana.bat 即可启动Kibana
2.2.3 Kinbana连接ES配置
解压并编辑config/kibana.yml,设置elasticsearch.url的值为已启动的ES,因为在默认情况下,Kibana会链接本地的默认ES http://localhost:9200
,如果需要修改链接的ES服务器,通过修改安装目录下 config/kibana.yml,将配置项 #elasticsearch.url: "http://localhost:9200"
取消注释即可修改连接的ES服务器地址。
2.2.4 测试Kibana
浏览器访问 http://localhost:5601 Kibana默认地址
Kibana组件详细说明地址:https://www.cnblogs.com/hunttown/p/6768864.html
常用的相关组件:
- Discover:可视化查询分析器
- Visualize:统计分析图表
- Dashboard:自定义主面板(添加图表)
- Timelion:Timelion是一个kibana时间序列展示组件(暂时不用)
- Dev Tools :Console(同CURL/POSTER,操作ES代码工具,代码提示,很方便)
- Management:管理索引库(index)、已保存的搜索和可视化结果(save objects)、设置 kibana 服务器属性。
当你进入UI操作界面时表示Kibana启动成功。
注:常见的启动报错:
原因:大概率是ES内存不够了,因为Kibana是要在ES中建立索引,需要占用ES的空间的,当空间不足,常见错误就是 Failed to poll for work 。
解决办法:许多的博客都有详细描述解决办法,这里就不再陈述。
3.操作ElasticSearch的相关命令
3.1 ElasticSearch的组成
3.1.1 Near Realtime(NRT)
近实时,两个意思,从写入数据到数据可以被搜索到有一个小延迟(大概1秒);基于es执行搜索和分析可以达到秒级。
3.1.2 Index:索引库
包含一堆有相似结构的文档数据,比如可以有一个客户索引,商品分类索引,订单索引,索引有一个名称。一个index包含很多document,一个index就代表了一类类似的或者相同的document。比如说建立一个product index,商品索引,里面可能就存放了所有的商品数据,所有的商品document。
3.1.3 Type:类型
每个索引里都可以有一个或多个type,type是index中的一个逻辑数据分类,·`一个type下的document,都有相同的field,比如博客系统,有一个索引,可以定义用户数据type,博客数据type,评论数据type。
3.1.4 Document&field
文档,es中的最小数据单元,一个document可以是一条客户数据,一条商品分类数据,一条订单数据,通常用JSON数据结构表示,每个index下的type中,都可以去存储多个document。一个document里面有多个field,每个field就是一个数据字段。
ElastciSearch全文搜索 | Mysql关系型数据库 |
---|---|
索引库(index) | 数据库(database) |
文档类型(Type) | 数据表(Table) |
文档(Document) | 一行数据(Row) |
字段(field) | 一个列(column) |
文档ID | 主键ID |
查询(Query DSL) | 查询(SQL) |
GET http://.. | SELECT * FROM ... |
PUT http:// | UPDATE table set... |
3.2 ElasticSearch索引库的CRUD操作命令
3.2.1 增加索引库
创建一个名字为 shopping
的索引库,5个Master Shard
分片,每个Master Shard分片有1个Replica Shard
从分片:
PUT shopping
{
"settings":{
"number_of_shards":5,
"number_of_replicas":1
}
}
3.2.2 查询索引库
查询所有索引库
GET _cat/indices?v
查看指定索引库
GET _cat/indices/aigou
3.2.3删除索引库
DELETE 名字
3.2.4修改索引库
先删除,再添加。
3.3 ElasticSearch文档的CRUD操作命令
3.3.1 添加文档
我们以员工对象为例,我们首先要做的是存储员工数据,每个文档代表一个员工。在ES中存储数据的行为就叫做索引(indexing),文档归属于一种类型(type),而这些类型存在于索引(index)中,我们可以简单的对比传统数据库和ES的对应关系:
ES | Mysql |
---|---|
_index(索引库) | 数据库 |
_type(文档类型) | 表 |
_document(文档对象) | 一行数据 |
_id(文档ID) | 主键ID |
field(字段) | 列 |
ES集群可以包含多个索引(indices)(数据库),每一个索引库中可以包含多个类型(types)(表),每一个类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。
例如:
PUT crm/user/11
{
"id":11,
"username":"zs",
"age":18,
"name":"zs",
"sex":1,
"join_date": 1584092062348
}
这是一个添加id为11的用户 , 索引库为 crm,类型为 User的一个实例。
3.3.2 获取文档
获取指定文档
GET 索引库/类型/文档ID
指定返回的列
GET /crm/user/123?_source=fullName,email
只要内容不要元数据
GET /crm/user/123/_source
3.3.3 修改文档
整体修改
全量修改的语法跟添加文档语法一样,如果文档已经存在就是添加,否则就是修改,
文档修改过程:1.标记删除旧文档,2.添加新文档
PUT {index}/{type}/{id}
{
"id":11,
"username":"zs"
}
注意:上面的修改会把ES中的数据全部覆盖,即age字段会消失
局部修改
局部修改过程: 1.检索旧文档 , 2.修改文档 ,3.标记删除旧文档 , 4.添加新文档
POST /crm/user/123/_update
{
"doc":{
"id" : 11,
"username": "xx"
}
}
注意:上面修改只会修改id,和username字段,age字段不会作任何改变。
3.3.4 删除文档
DELETE {index}/{type}/{id}
3.3.5 查询文档
查询所有
GET _search
查询指定索引库
GET crm/_search
查询指定类型
GET crm/user/_search
查询指定文档
GET crm/user/11
分页查询
&size=2&from=2
size: 每页条数
form:从多少条数据开始查
字符串查询
GET crm/user/_search?q=age:17&size=2&from=2&sort=id:desc&_source=id,username
注:字符串查询(query string)其实就是在url后面以字符串的方式拼接各种查询条件,这种方式不推荐,因为条件过多,拼接起来比较麻烦。
批量查询
批量查询很重要,对相比单个查询来说,批量查询性能更高。主要有两种方式:
- 不同索引库查询
GET _mget { "docs" : [ { "_index" : "itsource", "_type" : "blog", "_id" : 2 }, { "_index" : "itsource", "_type" : "employee", "_id" : 1, "_source": "email,age" } ] }
- 同索引库同类型 - 推荐
GET itsource/blog/_mget { "ids" : [ "2", "1" ] }
4.ElasticSearch的分词和相关映射
4.1 分词
4.1.1 概念
在全文检索理论中,文档的查询是通过关键字查询文档索引来进行匹配,因此将文本拆分为有意义的单词,对于搜索结果的准确性至关重要,因此,在建立索引的过程中和分析搜索语句的过程中都需要对文本串分词。ES的倒排索引是分词的结果。
4.1.2 作用
为了方便理解,我们用一个模拟图跟踪一下ES创建倒排索引的过程,如有原始数据:
ID | USERNAME | INTRO |
---|---|---|
1 | zs | my name is zs |
2 | ls | my name is ls |
如果对intro进行倒排索引,ES会根据分词器进行分词 , 语义转换,排序, 分组等操作最终倒排索引如下:
词元 | ID倒排 |
---|---|
is | 1 -> 2 |
ls | 2 |
my | 1 -> 2 |
name | 1 -> 2 |
zs | 1 |
当ES进行关键字查询的时候,如需要查询“my”
,那么ES可以根据二分查找更快的定位到 my | 1 -> 2
, 根据ID值1 ,2直接取出结果。
4.1.3 IK分词器
ES默认对英文文本的分词器支持较好,但和lucene一样,如果需要对中文进行全文检索,那么就需要使用中文分词器,同lucene一样,在使用中文全文检索前,需要集成IK分词器。
1.下载ES的IK分词器
插件源码地址:https://github.com/medcl/elasticsearch-analysis-ik
2.解压elasticsearch-analysis-ik-5.2.2.zip文件
并将解压后的内容放置于ES根目录/plugins/ik
3.IK分词器配置
在ik/config 目录可以对分词器进行配置,如停词 , 自定义字典等。
4.2 文档类型映射
4.2.1 概念
ES的文档映射(mapping)机制用于进行字段类型确认,将每个字段匹配为一种确定的数据类型。就如果Mysql创建表时候指定的每个column列的类型。 为了方便字段的检索,我们会指定存储在ES中的字段是否进行分词,但是有些字段类型可以分词,有些字段类型不可以分词,所以对于字段的类型需要我们自己去指定。需要注意的是,我们在Mysql建表过程是:
Mysql创建数据库 -> 创建表(指定字段类型) -> crud数据 而在ES中也是一样,
ES创建索引库 -> 文档类型映射 -> crud文档
1.默认的字段类型
查看索引类型的映射配置:GET {indexName}/_mapping/{typeName}
-
基本字段类型
字符串 | TEXT(分词) ; | KEYWORD(不分词) ; | STRINGFIELD(不分词文本); | TEXTFILED(要分词文本) | |
---|---|---|---|---|---|
数字 | long | integer | short | double | float |
日期 | date | ||||
逻辑 | boolean |
-
复杂字段类型
对象类型 | OBJECT |
---|---|
数组类型 | array |
地理位置 | geo_point,geo_shape |
-
默认映射
ES在没有配置Mapping的情况下新增文档,ES会尝试对字段类型进行猜测,并动态生成字段和类型的映射关系。
内容 | 默认映射类型 |
---|---|
JSON type | Field type |
Boolean: true or false | "boolean" |
Whole number: 123 | "long" |
Floating point: 123.45 | "double" |
String, valid date:"2014-09-15" | "date" |
String: "foo bar" | "text" |
2.映射规则
字段映射的常用属性配置列表 - 即给某个字段执行类的时候可以指定以下属性
==TYPE== | 类型:基本数据类型,INTEGER,LONG,DATE,BOOLEAN,KEYWORD,TEXT... |
---|---|
enable | 是否启用:默认为true。 false:不能索引、不能搜索过滤,仅在_source中存储 |
boost | 权重提升倍数:用于查询时加权计算最终的得分。 |
format | 格式:一般用于指定日期格式,如 yyyy-MM-dd HH:mm:ss.SSS |
ignore_above | 长度限制:长度大于该值的字符串将不会被索引和存储。 |
ignore_malformed | 转换错误忽略:true代表当格式转换错误时,忽略该值,被忽略后不会被存储和索引。 |
include_in_all | 是否将该字段值组合到_all中。 |
null_value | 默认控制替换值。如空字符串替换为”NULL”,空数字替换为-1 |
store | 是否存储:默认为false。true意义不大,因为_source中已有数据 |
==index== | 索引模式:analyzed (索引并分词,text默认模式), not_analyzed (索引不分词,keyword默认模式),no(不索引) |
==analyzer== | 索引分词器:索引创建时使用的分词器,如ik_smart,ik_max_word,standard |
==search_analyzer== | 搜索分词器:搜索该字段的值时,传入的查询内容的分词器。 |
| ==fields== | 多字段索引:当对该字段需要使用多种索引模式时使用。如:城市搜索 New York"city":"city":{ "type": "text", "analyzer": "ik_smart", "fields": { "raw": { "type": "keyword" } } } 解释:相当于给 city取了一个别名 city.raw,city的类型为text , city.raw的类型keyword 搜索 city分词 ; 搜索city.raw 不分词那么以后搜索过滤和排序就可以使用city.raw字段名 |
4.2.2. 添加映射
注意:如果索引库已经有数据了,就不能再添加映射了
1.创建新的索引库
put aigou
2.单类型创建映射
put aigou/goods/_mapping
{
"goods": {
"properties": {
"id": {
"type": "long"
},
"name": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
}
}
}
}
解释:给aigou索引库中的是goods类型创建映射 ,id指定为long类型 , name指定为text类型(要分词),analyzer分词使用ik,查询分词器也使用ik
3.多类型创建映射
PUT aigou
{
"mappings": {
"user": {
"properties": {
"id": {
"type": "integer"
},
"info": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
}
}
},
"dept": {
"properties": {
"id": {
"type": "integer"
},
....更多字段映射配置
}
}
}
}
解释:同时给user和dept创建文档映射
4.数组/对象映射
基本类型字段映射非常简单,直接配置对应的类型即可,但是数组和对象如何指定类型呢?
对象映射
{
"id" : 1,
"girl" : {
"name" : "王小花",
"age" : 22
}
}
文档映射
{
"properties": {
"id": {"type": "long"},
"girl": {
"properties":{
"name": {"type": "keyword"},
"age": {"type": "integer"}
}
}
}
}
数组映射
{
"id" : 1,
"hobby" : ["王小花","林志玲"]
}
文档映射
{
"properties": {
"id": {"type": "long"},
"hobby": {"type": "keyword"}
}
}
解释:数组的映射只需要映射一个元素即可,因为数组中的元素类型是一样的。
对象数组
{
"id" : 1,
"girl":[{"name":"林志玲","age":32},{"name":"赵丽颖","age":22}]
}
文档映射
"properties": {
"id": {
"type": "long"
},
"girl": {
"properties": {
"age": { "type": "long" },
"name": { "type": "text" }
}
}
}
4.2.3.全局映射
索引库中多个类型(表)的字段是有相同的映射,如所有的ID都可以指定为integer类型,基于这种思想,我们可以做全局映射,让所有的文档都使用全局文档映射。全局映射可以通过动态模板和默认设置两种方式实现。
-
默认方式:default
索引下所有的类型映射配置会继承default的配置,如:
PUT {indexName}
{
"mappings": {
"_default_": {
"_all": {
"enabled": false
}
},
"user": {},
"dept": {
"_all": {
"enabled": true
}
}
}
关闭默认的 all ,dept自定义开启 _all
-
动态模板
在实际应用场景中,一个对象的属性中,需要全文检索的字段较少,大部分字符串不需要分词,因此,需要利用全局模板覆盖自带的默认模板
PUT _template/global_template //创建名为global_template的模板
{
"template": "*", //匹配所有索引库
"settings": { "number_of_shards": 1 }, //匹配到的索引库只创建1个主分片
"mappings": {
"_default_": {
"_all": {
"enabled": false //关闭所有类型的_all字段
},
"dynamic_templates": [
{
"string_as_text": {
"match_mapping_type": "string",//匹配类型string username="xxx xxx"
"match": "*_text", //匹配字段名字以_text结尾
"mapping": {
"type": "text",//将类型为string的字段映射为text类型
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word",
"fields": {
"raw": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
},
{
"string_as_keyword": {
"match_mapping_type": "string",//匹配类型string
"mapping": {
"type": "keyword"//将类型为string的字段映射为keyword类型
}
}
}
]
}
}}
PS : 映射方式优先级 (低 -> 高):默认 -> 全局 -> 自定义