一 elasticsearch的基本概念
cluster | 整个elasticsearch 默认就是集群状态,整个集群是一份完整、互备的数据。 |
node | 集群中的一个节点,一般只一个进程就是一个node |
shard | 分片,即使是一个节点中的数据也会通过hash算法,分成多个片存放,默认是5片。(7.0默认改为1片) |
index | 相当于rdbms的database(5.x), 对于用户来说是一个逻辑数据库,虽然物理上会被分多个shard存放,也可能存放在多个node中。 6.x 7.x index相当于table |
type | 类似于rdbms的table,但是与其说像table,其实更像面向对象中的class , 同一Json的格式的数据集合。(6.x只允许建一个,7.0被废弃,造成index实际相当于table级) |
document | 类似于rdbms的 row、面向对象里的object |
field | 相当于字段、属性 |
GET /_cat/nodes?v 查询各个节点状态
GET /_cat/indices?v 查询各个索引状态
GET /_cat/shard/xxxx 查询某个索引的分片情况
索引结构对比
B+Tree
lucene 倒排索引结构
可以看到 lucene 为倒排索引(Term Dictionary)部分又增加一层Term Index结构,用于快速定位,而这Term Index是缓存在内存中的,但mysql的B+tree不在内存中,所以整体来看ES速度更快,但同时也更消耗资源(内存、磁盘)。
lucene与elasticsearch的关系
咱们之前讲的处理分词,构建倒排索引,等等,都是这个叫lucene的做的。那么能不能说这个lucene就是搜索引擎呢?
还不能。lucene只是一个提供全文搜索功能类库的核心工具包,而真正使用它还需要一个完善的服务框架搭建起来的应用。
好比lucene是类似于发动机,而搜索引擎软件(ES,Solr)就是汽车。
目前市面上流行的搜索引擎软件,主流的就两款,elasticsearch和solr,这两款都是基于lucene的搭建的,可以独立部署启动的搜索引擎服务软件。由于内核相同,所以两者除了服务器安装、部署、管理、集群以外,对于数据的操作,修改、添加、保存、查询等等都十分类似。就好像都是支持sql语言的两种数据库软件。只要学会其中一个另一个很容易上手。
从实际企业使用情况来看,elasticSearch的市场份额逐步在取代solr,国内百度、京东、新浪都是基于elasticSearch实现的搜索功能。国外就更多了 像维基百科、GitHub、Stack Overflow等等也都是基于ES的。
二 elasticsearch restful api (DSL)
DSL全称 Domain Specific language,即特定领域专用语言。
es中保存的数据结构
public class Movie {
String id;
String name;
Double doubanScore;
List<Actor> actorList;
}
public class Actor {
String id;
String name;
}
所以他保存到es中应该是:这两个对象如果放在关系型数据库保存,会被拆成2张表,但是elasticsearch是用一个json来表示一个document。
{ “id”:”1”, “name”:”operation red sea”, “doubanScore”:”8.5”, “actorList”:[ {“id”:”1”,”name”:”zhangyi”}, {“id”:”2”,”name”:”haiqing”}, {“id”:”3”,”name”:”zhanghanyu”} ] } |
对数据的操作
查看es中有哪些索引
GET /_cat/indices?v |
es 中会默认存在一个名为.kibana的索引
表头的含义
PUT /movie_index |
增加一个索引
health | green(集群完整) yellow(单点正常、集群不完整) red(单点不正常) |
status | 是否能使用 |
index | 索引名 |
uuid | 索引统一编号 |
pri | 主节点几个 |
rep | 从节点几个 |
docs.count | 文档数 |
docs.deleted | 文档被删了多少 |
store.size | 整体占空间大小 |
pri.store.size | 主节点占 |
删除一个索引
ES 是不删除也不修改任何数据的,而是增加版本号
DELETE /movie_index |
新增文档
格式 PUT /index/type/id
PUT /movie_index/movie/1 { "id":1, "name":"operation red sea", "doubanScore":8.5, "actorList":[ {"id":1,"name":"zhang yi"}, {"id":2,"name":"hai qing"}, {"id":3,"name":"zhang han yu"} ] } PUT /movie_index/movie/2 { "id":2, "name":"operation meigong river", "doubanScore":8.0, "actorList":[ {"id":3,"name":"zhang han yu"} ] }
PUT /movie_index/movie/3 { "id":3, "name":"incident red sea", "doubanScore":5.0, "actorList":[ {"id":4,"name":"zhang chen"} ] } |
如果之前没建过index或者type,es 会自动创建。
直接用id查找
GET movie_index/movie/1 |
修改—整体替换
和新增没有区别 要求:必须包括全部字段
PUT /movie_index/movie/3 { "id":"3", "name":"incident red sea", "doubanScore":"5.0", "actorList":[ {"id":"1","name":"zhang chen"} ] } |
修改—某个字段
POST movie_index/movie/3/_update { "doc": { "doubanScore":"7.0" } } |
删除一个document
DELETE movie_index/movie/3 |
搜索type全部数据
GET movie_index/movie/_search |
结果
{ "took": 2, //耗费时间 毫秒 "timed_out": false, //是否超时 "_shards": { "total": 5, //发送给全部5个分片 "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 3, //命中3条数据 "max_score": 1, //最大评分 "hits": [ // 结果 { "_index": "movie_index", "_type": "movie", "_id": 2, "_score": 1, "_source": { "id": "2", "name": "operation meigong river", "doubanScore": 8.0, "actorList": [ { "id": "1", "name": "zhang han yu" } ] } 。。。。。。。。 。。。。。。。。 } |
按条件查询(全部)
GET movie_index/movie/_search { "query":{ "match_all": {} } } |
按分词查询
GET movie_index/movie/_search { "query":{ "match": {"name":"red"} } } |
按分词子属性查询
GET movie_index/movie/_search { "query":{ "match": {"actorList.name":"zhang"} } } |
match phrase
GET movie_index/movie/_search { "query":{ "match_phrase": {"name":"operation red"} } } |
按短语查询,不再利用分词技术,直接用短语在原始数据中匹配
fuzzy查询
GET movie_index/movie/_search { "query":{ "fuzzy": {"name":"rad"} } } |
校正匹配分词,当一个单词都无法准确匹配,es通过一种算法对非常接近的单词也给与一定的评分,能够查询出来,但是消耗更多的性能。
过滤--查询后过滤
GET movie_index/movie/_search { "query":{ "match": {"name":"red"} }, "post_filter":{ "term": { "actorList.id": 3 } } } |
过滤--查询前过滤(推荐使用)
GET movie_index/movie/_search { "query":{ "bool":{ "filter":[ {"term": { "actorList.id": "1" }}, {"term": { "actorList.id": "3" }} ], "must":{"match":{"name":"red"}} } } } |
过滤--按范围过滤
GET movie_index/movie/_search { "query": { "bool": { "filter": { "range": { "doubanScore": {"gte": 8} } } } } } |
关于范围操作符:
gt | 大于 |
lt | 小于 |
gte | 大于等于 great than or equals |
lte | 小于等于 less than or equals |
排序
GET movie_index/movie/_search { "query":{ "match": {"name":"red sea"} } , "sort": [ { "doubanScore": { "order": "desc" } } ] } |
分页查询
GET movie_index/movie/_search { "query": { "match_all": {} }, "from": 1, "size": 1 } |
指定查询的字段
GET movie_index/movie/_search { "query": { "match_all": {} }, "_source": ["name", "doubanScore"] } |
高亮
GET movie_index/movie/_search { "query":{ "match": {"name":"red sea"} }, "highlight": { "fields": {"name":{} } }
} |
聚合
取出每个演员共参演了多少部电影
GET movie_index/movie/_search { "aggs": { "groupby_actor": { "terms": { "field": "actorList.name.keyword" } } } } |
每个演员参演电影的平均分是多少,并按评分排序
GET movie_index/movie/_search { "aggs": { "groupby_actor_id": { "terms": { "field": "actorList.name.keyword" , "order": { "avg_score": "desc" } }, "aggs": { "avg_score":{ "avg": { "field": "doubanScore" } } } } } } |
聚合时为何要加 .keyword后缀?
.keyword 是某个字符串字段,专门储存不分词格式的副本 ,在某些场景中只允许只用不分词的格式,比如过滤filter 比如 聚合aggs, 所以字段要加上.keyword的后缀。
三 中文分词器
elasticsearch本身自带的中文分词,就是单纯把中文一个字一个字的分开,根本没有词汇的概念。但是实际应用中,用户都是以词汇为条件,进行查询匹配的,如果能够把文章以词汇为单位切分开,那么与用户的查询条件能够更贴切的匹配上,查询速度也更加快速。
分词器下载网址:https://github.com/medcl/elasticsearch-analysis-ik
安装
下载好的zip包,请解压后放到 …/elasticsearch/plugins/ik
然后重启es
默认分词器会将汉字拆分成一个一个单个汉字,使用其他分词器可根据中文语法特点将原先的此拆分成更多的有含义的词。