本文共 9013 字,大约阅读时间需要 30 分钟。
cluster | 整个elasticsear----ch 默认就是集群状态,整个集群是一份完整、互备的数据。 |
node | 集群中的一个节点,一般只一个进程就是一个node |
Shard | 分片,即使是一个节点中的数据也会通过hash算法,分成多个片存放,默认是5片。 |
Index | 相当于rdbms的database, 对于用户来说是一个逻辑数据库,虽然物理上会被分多个shard存放,也可能存放在多个node中。 |
Type | 类似于rdbms的table,但是与其说像table,其实更像面向对象中的class , 同一Json的格式的数据集合。 |
Document | 类似于rdbms的 row、面向对象里的object |
Field | 相当于字段、属性 |
public class Movie { String id; String name; Double doubanScore; ListactorList;}public class Actor{ String id;String name;}
这两个对象如果放在关系型数据库保存,会被拆成2张表,但是elasticsearch是用一个json来表示一个document。
所以它保存到es中应该是:{ “id”:”1”, “name”:”operation red sea”, “doubanScore”:”8.5”, “actorList”:[ { “id”:”1”,”name”:”zhangyi”}, { “id”:”2”,”name”:”haiqing”}, { “id”:”3”,”name”:”zhanghanyu”} ]}
es 中会默认存在一个名为.kibana的索引 表头的含义GET /_cat/indices?v
health | green(集群完整) yellow(单点正常、集群不完整) red(单点不正常) |
status | 是否能使用 |
index | 索引名 |
uuid | 索引统一编号 |
pri | 主节点几个 |
rep | 从节点几个 |
docs.count | 文档数 |
docs.deleted | 文档被删了多少 |
store.size | 整体占空间大小 |
pri.store.size | 主节点占 |
PUT /movie_index
ES 是不删除也不修改任何数据 ,伪删除更新当前index的版本。
DELETE /movie_index
格式 PUT /index/type/id
例:(如果之前没建过index或者type,es 会自动创建。)
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":"liu de hua"} ]}
GET movie_index/movie/1
和新增没有区别
PUT /movie_index/movie/3{ "id":"3", "name":"incident red sea", "doubanScore":"5.0", "actorList":[ { "id":"1","name":"zhang guo li"} ]}
POST movie_index/movie/3/_update{ "doc": { "doubanScore":"7.0" } }
DELETE movie_index/movie/3
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"} }}
GET movie_index/movie/_search{ "query":{ "match_phrase": { "name":"operation red"} }}
按短语查询,不再利用分词技术,直接用短语在原始数据中匹配
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 } }}
其实准确来说,ES中的查询操作分为2种:查询(query)和过滤(filter)。查询即是之前提到的query查询,它(查询)默认会计算每个返回文档的得分,然后根据得分排序。而过滤(filter)只会筛选出符合的文档,并不计算得分,且它可以缓存文档。所以,单从性能考虑,过滤比查询更快。
换句话说,过滤适合在大范围筛选数据,而查询则适合精确匹配数据。一般应用时,应先使用过滤操作过滤数据,然后使用查询匹配数据。GET movie_index/movie/_search { "query":{ "bool":{ "filter":[ { "term": { "actorList.id": "1" }}, { "term": { "actorList.id": "3" }} ], "must":{ "match":{ "name":"red"}} } } }
term、terms过滤
term、terms的含义与查询时一致。term用于精确匹配、terms用于多词条匹配。不过既然过滤器适用于大氛围过滤,term、terms在过滤中使用意义不大。在项目中建议使用term。 Term: where id = ? Terms: where id in () # select * from skuInfo where id=? # select * from skuInfo where id in ()GET movie_index/movie/_search{ "query": { "bool": { "filter": { "range": { "doubanScore": { "gte": 8} } } } }}
关于范围操作符:跟html标签中的转义字符一样!
gt 大于 lt 小于 gte 大于等于 lte 小于等于
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{ "query":{ "match": { "name":"red sea"} }, "highlight": { "post_tags": [""], "pre_tags": [""], "fields": { "name":{ } } }}
取出每个演员共参演了多少部电影 – sql : group by
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" } } } } }}
之前说type可以理解为table,那每个字段的数据类型是如何定义的呢
查看mappingGET movie_index/_mapping/movie
实际上每个type中的字段是什么数据类型,由mapping定义。但是如果没有设定mapping系统会自动,根据一条数据的格式来推断出应该的数据格式。
true/false → boolean
1020 → long 20.1 → double,float “2018-02-01” → date “hello world” → text + keyword
默认只有text会进行分词,keyword是不会分词的字符串。mapping除了自动定义,还可以手动定义,但是只能对新加的、没有数据的字段进行定义。一旦有了数据就无法再做修改了。
注意:虽然每个Field的数据放在不同的type下,但是同一个名字的Field在一个index下只能有一种mapping定义。
elasticsearch本身自带的中文分词,就是单纯把中文一个字一个字的分开,根本没有词汇的概念。但是实际应用中,用户都是以词汇为条件,进行查询匹配的,如果能够把文章以词汇为单位切分开,那么与用户的查询条件能够更贴切的匹配上,查询速度也更加快速。
分词器下载网址:1.下载好的zip包,请放到 /usr/share/elasticsearch/plugins/ 下解压
[root@localhost plugins]# unzip elasticsearch-analysis-ik-5.6.4.zip2.将压缩包文件删除!否则启动失败!
3.然后重启es
[root@localhost plugins]# service elasticsearch restart使用默认
GET movie_index/_analyze{ "text": "我是中国人"}
请观察结果使用分词器
GET movie_index/_analyze{ "analyzer": "ik_smart", "text": "我是中国人"}
请观察结果
另外一个分词器 ik_max_word
GET movie_index/_analyze{ "analyzer": "ik_max_word", "text": "我是中国人"}
请观察结果
能够看出不同的分词器,分词有明显的区别,所以以后定义一个type不能再使用默认的mapping了,要手工建立mapping, 因为要选择分词器。1、建立mapping
PUT movie_chn{ "mappings": { "movie":{ "properties": { "id":{ "type": "long" }, "name":{ "type": "text" , "analyzer": "ik_smart" }, "doubanScore":{ "type": "double" }, "actorList":{ "properties": { "id":{ "type":"long" }, "name":{ "type":"keyword" } } } } } }}
2.插入数据
PUT /movie_chn/movie/1{ "id":1, "name":"红海行动", "doubanScore":8.5, "actorList":[ { "id":1,"name":"张译"}, { "id":2,"name":"海清"}, { "id":3,"name":"张涵予"} ]}PUT /movie_chn/movie/2{ "id":2, "name":"湄公河行动", "doubanScore":8.0, "actorList":[ { "id":3,"name":"张涵予"} ]}PUT /movie_chn/movie/3{ "id":3, "name":"红海事件", "doubanScore":5.0, "actorList":[ { "id":4,"name":"张国立"} ]}
3.查询测试
GET /movie_chn/movie/_search{ "query": { "match": { "name": "红海战役" } }}GET /movie_chn/movie/_search{ "query": { "term": { "actorList.name": "张译" } }}
什么时候使用? 当词库满足不了你的需要,可以使用自定义词库!
1.修改/usr/share/elasticsearch/plugins/ik/config/中的IKAnalyzer.cfg.xml
IK Analyzer 扩展配置 http://192.168.xx.xxx/fenci/myword.txt
2.按照标红的路径利用nginx发布静态资源
在nginx.conf中配置server { listen 80; server_name 192.168.xx.xxx; location /fenci/ { root es; } }
3.并且在/usr/local/nginx/下建/es/fenci/目录,目录下加myword.txt
在myword.txt中编写关键词,每一行代表一个词。4.然后重启es服务器,重启nginx。在kibana中测试分词效果
5.配置完成分词之后,要重启es .
若分词失败:看日志 cd /var/log/elasticsearch/ vim my-es.log 更新完成后,es只会对新增的数据用新词分词。历史数据是不会重新分词的。 如果想要历史数据重新分词。需要执行:POST movies_index_chn/_update_by_query?conflicts=proceed
转载地址:http://gpshn.baihongyu.com/