https://blog.youkuaiyun.com/qq_26803795/article/details/81482856
1.倒排索引
类似于以下结构
1 宋茂林的家人
2 宋茂林的电影
3 宋茂林的狗
关键字 ids
宋茂林 123
家人 1
电影 2
狗狗 3
我们可以在建立倒排时候,把同义词等加入,复数转单数(normalization)
当我们检索时候 搜索宋茂林的猫,分成宋茂林 猫 ,在倒排索引重搜索,宋茂林找到123 猫没找到,返回的就是123的id数据。
比数据库的模糊查询效率高,我们这可能直接一次就查询出来了,数据库要全表扫。数据库也不能分词。
2 lucene
就是一个jar 包含了倒排索引的建立,搜索的code, 包括很多算法,可以把已有的数据建立索引,在本地磁盘上给我们组织索引的数据结
构
基于Lucene的
保证了数距的高可用,保证了索引的建立在多个节点上,查询时候也到各个节点查询。提供了一些高及查询,如查询地理位置1公里的烤肉
店。
分布式的搜索引引擎 数据分析引擎(销量前十的)
搜索:全文检索
结构化检索(有过滤的等) 过滤的是一个结构
等
3kibana
控制台 管理 es的,可提供各种数据, 如 集群的健康状态 indeies curd等 端口 5601
es端口9200
https://www.cnblogs.com/yiwangzhibujian/p/7137546.html
index 相当于 数据库
type 相当于表
document 相当于数据的一行
4crud
查询 get /index/type/1
创建 put /index/type/1
{结构化json数据}
修改 put /index/type/1{结构化json数据} 这样这个数据就被覆盖掉了 ,用put是替换json的数据
post /index/type/1/_update {"doc":{name:"sss"}} 这样是修改1的namefiled属性,其他属性还是以前的s
partial update
post /index/type/1/update{
"doc":{feidl:value}
}
我们用 partial update 1.减少交互,前者的先查,再写,后者直接在es写,2减少并发冲突,前者查询在写时间长,后者在es操作毫秒级
当我们partial update修改时候 发现版本号小了(可能有其他的线程操作完成了),这个时候我们可以指定retry侧率,
retry_on_confilct=5,retry5次,或者手动指定version保证数据写入es中
删除 delete /index/type/1 只是一个标记删除 ,不是真的物理删除,当到阀值时候后台删除
修改删除 会增加version 这个用来保证数据的一致性的 ,多个节点赋值数据的时候。乐观锁
get /_cat/health jiancha集群的健康状态
get /jiqun名/indeies 查看索引
kibana 启动时候,在es上创建一个索引,用一个shard主一个shard从来存储,默认es一个索引是5个主5个从的。
当启动一个es节点时候,shard启动率50%,只有一个主,从没有
nrt 近实时 ,es存储数据默认1秒后才能查询到。
5搜索方式
query string search 不会用
类似于url参数在?
全部查询
get /index/type/_search
查询过滤
get /index/type/_search?q=name:yaogao&sort=price:desc
get /index/type/_search?q=+name:yaogao 与上面的一致 必须包含
get /index/type/_search?q=-name:yaogao name列必须不包含yaogao
get /index/type/_search?q=test 不管哪个feild包含test 就返回,我们是对每个field都进行搜索妈,不是的,运用了_all这个元数
据。
_all:es创建一个document,吧所有的feild以字符串的形式拼接,形成一个新的字符串,这个字符串就是就是_all feild的值,建立倒排索
引,搜索时候没指定feild ,那么就查_all
query dsl 结构体查询
get /index/type/_search
{
“query”:{“match_all”:{}}
}
get /index/type/_search
{
"query":{
"match":{"name":"yaogao"}
},
"sort":[{"price":"desc"}]
}
}
分页
from size 先搜索所有的 之后用from size限制
get /index/type/_search
{
"query":{"match_all":{}},
"from":2,
"size":1
}
查询指定feild _source
get /index/type/_search
{
"query":{
"match":{"name":"yaogao"}
},
"_source":["name","price"]
}
过滤 filter
多个查询条件应封装到bool的json中 bool 是组合查询
get /index/type/_searche
{
"query":{
"bool":{
"must":{
"match”:{"name":"yaogao"}
},
“filter”:{
"range":{
"price":{"gt","25"}
}
}
}
}
}
全文检索 把词分了 ,各个词都去指定的index索引指定的feidl 去匹配 ,由匹配度不同而返回不同的maxsroce
get /index/type/_search
{
"query":{
"match":{
producer:"yaogao prodces"
}
}
}
全文检索会先把关键词分词
短语检索 match_phrase关键词不分词
get /index/type/_search
{
"query":{
“match_phrase”:{
producer:"yaogao prodces"
}
}
}
高亮 highlighjt
group by 等聚合分析
1计算每个tag下的商品数量 aggs 聚合 terms
get /index/type/_search
{
"aggs":{
"group_by_tag":{
"terms":{"field":"tag"}
}
}
}
执行这个语句会报错,提示要修改tag的filecdate属性为true
put /index/_mapping/type
{
"properties":{
"tags":{
"type":"text",
"fileddate":"true"
}
}
}
修改索引的mapping
聚合时候会把原始数据放到返回结果,我们设置“size”:0 ,可以吧原始数据过滤掉,与aggs 同级
先分组 计算每组平均值 avg 嵌套聚合
get /index/type/_search
{
size”:0,
"aggs":{
"group_by_tag":{
"terms":{
"feild":"tags"
},
"aggs":{
"avg_price":{
"avg":{
"feild":"price"
}
}
}
}
}
}
按照平均价格降序排序
get /index/type/_search
{
"size":0,
"aggs":{
"group_by_tags":{
“terms”:{
"feild":"tags",
"order":{
"avg_price":"desc"
}
},
“aggs”:{
“avg_price”:{
"feild":"price"
}
}
}
}
}
按照指定的价格范围区间进行分组,然后在每组内在按照tag进行分组,最后计算每组的平均价格
get /index/type/_search{
"size":0,
"aggs":{
”group_by_price”:{
“range”:{
"feild":"price",
"ranges":[
{ "from":0,
"to":20
},
{ "from":20,
"to":40
},
{ "from":40,
"to":60
}
]
},
"aggs":{
"group_by_tags":{
“terms”:{
"feild":"tags",
"order":{
"avg_price":"desc"
}
},
“aggs”:{
“avg_price”:{
"feild":"price"
}
}
}
}
}
}
}
-----------------------------------------------------------------------------------------------
6 es对分布式机制的隐藏特性
分片机制隐藏了,数据保存了,数据到底放到哪个shard,
新启动一个节点,这个节点是如何加到集群的?数据是如何放到这个新的节点的?
shard负载 有3个节点,25个shard(5个index),es吧这25geshard平均分到3个节点
数据读取时候,是如何请求有数据的节点的?
7扩容是怎们做的
8.节点增加减少时候 es 会rebalance
当节点新增了,es自动会吧原来节点放多个shard的,移动一些shard到新的节点,为了负载,这就是es 自动reblance
9master 节点
https://blog.youkuaiyun.com/J_bean/article/details/80147277
master存储元数据,索引的创建删除,节点增加移除 。默认选出一个marster
---------------------------------------------------------------------------------------------
一个index包含一个或多个shard,每个shard放到不同节点上。
shard是数据最小的存储单元,每个shard就是luncen的实例,完成的建立索引数据请求的能力
增加删除节点,shard会自动的负载到节点上。
primary shard replica shard 一个document只会存储在一个primary shard里(和对应的replica shard)。不会存在于多个
primaryshard
primary shard 在创建索引时候就已经固定了,replica shard数量课修改
默认 5个primary replica 1 意思就是5个prmaryshard ,每个主都有一个replica 一共10个shard
每个primaryshard 不能与自己的replicashard放在一个节点上
单台node 创建index 什么样
创建索引3个primary shard 3个replica
put /index_name
{"setting":{
"number_of_shards":3,
"number_of_replica":1
}
}
这时候直飞配3个primary ,3个replica不分配的。
当一个节点加入,此时有2个节点
那么新增加的节点会有3个replicashard
在加一个节点 那么可能把第一个节点的 p1 放到新增的节点,第二个节点的r2放到新增节点,(一个primaryshard不能与他的从放到一
个节点)
节点扩展瓶颈
索引一共分3个shard ,我们就放3个节点,每个主节点 都放到不同的节点上,这时候我们想再加人2节点提高性能,我们新增的节点放
replicashard,primarshard 分配后就不能变了。
当有6台节点3个primar 3个replica 这个情况时候最多能容忍1台服务器宕机
三台节点,3个primar shard,提升容错率 把replica=2,就一个又9个shard ,每个节点3个shard,每个节点都保证有3不同的shard
容忍2台服务宕机
容错过程
上个例子 当master节点挂了(p0,r1,r2),装填立刻变成red
马上master选举,新master将丢失的primaryshard 的replica变成primary ,状态变成yellow(replica没了,变成了primary了)
从起故障node,将缺失的副本copy一份到该node(使用以前的数据,同步一下宕机后的修改)状态变成green
集群状态
red 不是所有的primary shard 都是active
yellow 不是所有的shard 都是active
green 所有shard active
元数据
_index
_type 分表 有不同的feild
_id
不同类型的数据 放到不同的index里 如产品索引创建一个 物流数据放到一个 ,就是类似于分库
相同功能的数据放到一个index
三者加一起 唯一定位一个document
document id
手动指定 自动生成
什么时候手动指定 :一般从其他的系统数据导入es时候。
我们自己的系统就用es存储 这个时候就用自动生成
put /index/type/id{}
post /index/type{}
自动生成id长度20 url安全base64编码的 guid(分布式并行生成id不会导致冲突)----------------------------?-----------------------
https://blog.youkuaiyun.com/dukesword/article/details/7945157
_source 元数据 返回指定的fieild
get /index/type/_search?_source=feildname,filedname2
get /index/type/_search
{
“query”:{
"match_all":{}
},
"_source":["feildname","filedname2"]
}
document 全量替换
和创建一样,如果存在就全量替换
put /index/type/1{ json}
post /index/type/1/_update{json} ,这个json不是直接全部替换,而是看之前的json若属性有则替换属性值,没有的新增属性
document 是不可变的 ,修改 增量和全量替换都是把原来标记为删除 新增一个document,当es中数据越来越多时候,标记为delete
的都删除掉,释放空间。
强制创建
put /index/type/1/_create{} 或者 put /index/type/1?op_type=create 有会报错
es并发冲突
读取库存 用户下单 更新库存,多用户多线程更新库存导致库存错误
es 使用乐观锁(version)防治并发冲突
主从复制 也是基于version 当更新的数据所带版本号小于es存储数据版本号时候这个更新无效
并发修改一个值时候 修改数据所带版本号小于数据版本号时候 拿到es存储的值再进行修改
es 可以用自己的_vesrion 进行并发控制 (?version=1 版本号等于才能更新)------------------???????????
es 也可以用 external version(自己数据的版本号) ?version=1&version_type=external 版本号大于才能更
es groovy 脚本
内部脚本
post /index/type/11/_update{
"script":"ctx._source.num+=1"
}
外部脚本
我们在es的安装目录 config /scripte/新增一个脚本test-add.groovy加入内容
ctx._source.tags+=new_tag
post /index/type/11/_update
{
"script":{
“lang”:“groovy”
"file":"test-add",
"params":{
“new_tag”:“tag1”
}
}
}
ctx.op 操作
用脚本删除文档
写一个脚本deletgv
ctx.op=ctx._source.num==count?'delete':'none'
post /index/type/11/_update
{
"lang":"groovy",
"script":{
file:"deletgv",
params:{
count:0
}
}
}
upsert 文档没有了初始化操作 有更新
post /index/type/11/_update
{
"script":"ctx._source.num+=1",
"upsert":{
"num":0.
"tags":[]
}
}
批量查询 mget 减少网络开销
get /_mget{
"docs":[
{ “_index”:“名”,
“_type”:“名”,
“_id”:1
},
{ “_index”:“名”,
“_type”:“名”,
“_id”:2
}
]
}
一个index 不同type
get /index/_mget{
“docs”:[
{
“_type”:“名”,
“_id”:1
},
{
“_type”:“名”,
“_id”:2
}
]
}
一个index 一个type
get /index/type/_mget{
"ids":[1,2]
}
bulk 同一个json不能换行 ,不同的json有一个换行
为甚么这个格式呢,直接用换行符切割 ,22组成一组,路由到相应的shard,不会有内存占用太大。
不用着样的格式,我们没换行,我们先把这个json转成数据一样的jsonarry,通过这个jsonarry把数据路由到shard上去。这样占用内存
很多,要多一倍。
一个失败是不影响其他的操作的
delete create (强制创建_create) index(就是put,创建或全部的覆盖) update(partial update)
post /_bulk
{ "delete":{"_index":"name","_type":"ming","_id":1}}
{"create":{"_idnex":"ming","_type":"ming","_id":1}}
{"feild1":"dsfs","filed2":"dfsdsf"}
{"index":{"_index":"ming","_type":"ming"}}
{"feild1","idzidong"}
{"update":{"_index":"ming","_type":"ming","_id":1,"_retry_on_conflict":5}}
{"doc":{feidl:value}}
post /index/_bulk
post /index/index/_bulk
我们要反复尝试bulksize的大小,这些都加入内存,定不好的话影响性能2000-5000尝试 10m左右
document routing
保存一个document 具体放到哪个shard上
hash(rotuteing)%number_of_primary_shard
routing 默认就是documentid,也可以手动指定routing值 put /index/type/1?routing=useid 保证每一类型的数据路由到同一个
shard上去
每个index建立 他的primary shard 不可更改,这样才知道具体路由没问题
任何一个node都知道哪个shard在哪个节点上。
当一个请来了 访问任何一个节点(这个节点就就可以叫做协调节点 coordinate note)
根据ducumentid算出具体在那个primary shard上,并路由到那个节点,进行操作(增删改只能路由到primary shard),操作完,把
数据发送到replicashard ,都完成后 返回操作结果给协调节点,并返回给客户端。
这有一个异步操作,可以指定没有同步到replica完就可以吧结果返回给协调节点,返回给客端
---------------?????????????????????????------------------------
consistency 我们在 put/dddfsd/dfdf/1 时候可以指定这个?consistency=one quorum all
one document在primary shard 上是active 就可以执行操作
qurum 大部分的shard是active就可以执行(默认的)
all 所有的shard是ative就可以执行
quorum 不齐 es 就会等待 希望shard active 数量增加 ,时间到了 就timeout 我们也可以指定?timeout=10s
primary shard 与replicashard 不能放一起
同一个的primary shard 的replica 不能放一起
document查询请求 内部流程,与增删改差不多,路由的时候可以路由到replica(随机轮询),当我路由到一个replica shard,但是这
个shard 还内有同布docuemnt ,这个时候提示找不到,当同步完成后,可以查询了。
默认是没有timeout的,正常es 会吧所有的结果搜索完成返回回来,当指定timeout时候,我们就设定的时间把查询到的结果返回回来。
multi-index multi-type
get /index1,index2/
也可用通配符*
分页
put /index/type/_search?from=0&size=3
put /index/type/_search?from=3&size=3
深度分页 deep paging
3000条数据,3个shard ,每个shard1万,每页10条,搜索5000-5009,每个shard都要返回搜索5000-500910条数据,到一个节点上
汇总,拿出排序的10条,真的是这样吗?不是的
请求到协调节点上,把请求route在相应的shard,每个shard将内部的数据0-5009这些数据,每个shard都会吧这些收据传给协调节点,
协调节点排序,取自己需要的页数数据。
搜锁太深的时候在协调节点保存大量数据,还要排序,性能不好。
mapping
我们put 创建数据时候,会有一个dynamic mapping,自动为我们建立index,创建type 已经type对应的mapping,mapping包含每
个feild对应的数据类型(可能是 full text extatc value),如何分词等设置。也可以手动创建index type mapping 在创建数据时。
get /index/_mapping/type
es 2种模式的搜索
exact value 值完全一样 必须输入2017-01-10 这样才能搜索出来 2017-01-10的数据
full text 输入01 就能把2017-01-10这样的数据查询出来
(缩写、格式转化 大小写 同义词)这些可以根据fulltext查询出来,指定不同的分词器就行
分词器
功能1.分词 2normaliation
组成部分
character filter 进行预处理 如把《span》hello《span》 转成hello 1&2 ->1 and 2
tokenizer 分词
token filter 单复数转换 同义词转换 大小写转换等
es 内置分词器
standard analyzer
simple analyzer
whitespace analyzer
language analyzer
查询时候 先会分词,我们使用什么分词器呢,es会使用对应的feild建立倒排索引时候所用的分词器
不同类型的feild 有的查询就是fulltext 有的局势extact vlaue
date 就是 extatc value
_all shi full text
get /index/type/_search?q=post_date:2017
date类型是extact value 的 ,为什么这个记录会查出一条信息呢?——————————?????————————————————
mapping 数据类型
string byte short integer long float double boolean date
es 根据值推测类型
数字-》long yyyy-dd -》date 小数-》double
手动建立mapping 只能新增一个feild mapping 不能修改
put /indexname
{
"mappings":{
"typename":{
"properties":{
"filename":{
"type":"typename"
},
"filename":{
"type":"typename",
“analyizer”:
},
"filename":{
"type":"typename"
“index”:“not_analyzers”
}
}
}
}
}
不让分词 “index”:“not_analyzers” “index”:“analyzers” 分词 “index”:“no” 不让检索
type keywords 表示不会分词
不能修改 只能给type 加feild
put /index/_mapping/type{
"properties":{
“feildname”:{
。。。。。
}
}
}
put /index/_analyzer
{
"feild":“filename”,
“text”:“地方水电费第三方”
}
bool 组合多个条件
must[] 必须匹配
should[] 相当于or
must_not [] 必须不匹配
minimum_should_match:1 最小匹配为1------------------------------------???------------------------------------------
filter query对比
filter只是过滤数据,对相关度 没有任何影响,query每个document会去算相应的相关度,并按大到小排序。
filter不计算相关度 ,不排序,有内置的cache效率很高。
如何只用filter constant_score
get /_search{
"query":{
"constant_srcore":{
“filter”:{
“range”:{
"age":{
"gte":30
}
}
}
}
}
}
multi_match:{
“query”:“fssdsfs”,
feilds:["feild1",feild2]
}
range
get /_search{
"query":{
"range":{
"age":{
"gte":20,"lt":30
}
}
}
}
term 把值当成extact value 去查 match 会去分词查询
get /_search{
query:{
"term ":{
"filedname":"a b"
}
}
terms
get /_search{
query:{
"terms ":{
"filedname":["a b","b c"," c d"]
}
}
a b ,b c ,c d 都不分词
判断你的搜索合不合法
get /index/type/_validate/query?explain
{body}
对string 字符串排序 往往是不准的,因为string 已经被分词了,排序时候可能不是按照原来的string排序了,吧这个sting索引两次
一个用来分词 一个用来排序
put /index
{
"mappings":{
"typename":{
"properties":{
"title":{
type:string,
ananlyzer:english ,
"feilds":{
"raw":{
"type":"string”,
index:"not_analyzed"
}
},
feilddate:ture //正排索引-----------------------------------------------?????????????-----------------
}
}
}
}
}
之后用title.raw 去sort
TF/IDF
相关度评分
1.搜索文本中的各个词条在feild出现都少次 ,出现的高 ,相关度高
比如 hello word
doc1:hello yu word is good
doc2: word isbad
hello 在doc1出现1次 doc2 0,word doc1 doc2 都出现1次,doc1 相关度高
2.搜索文本中的各个词条在整个索引的所有文档中出现的次数,次数越多,相关就越di
比如 比如 hello word
hellow 所有文档出现10000次,word所有文档出100次,
doc1:hello yu is good
doc2: word isbad
doc2的相关度就高于doc1
3filed 长度越长 相关度月小
如hellow word
doc1:有一个短小的filed 包含hello
doc2 有一个长度大的feidl 包含word
1.2都一样的话,那么3的相关度doc1高,出现在小的filed里。
在查询的时候_serach?explain就能知道评分是如何算出来的
搜索的时候用倒排索引 排序时候用正排索引(聚合等都用的正派索引)
正排索引 就是 doc values
doc1: {name :song,age:20}
doc1: {name :song1,age:21}
建立的正排索引就是
document name age
doc1 song 20
doc2 song1 21
排序按age拍就直接sortage大小就ok了,
创建索引时候 正派倒排都建立好了
query phase
来一个请求,请求的协调节点将建立一个priority queue ,大小有请求的 from size决定,form为1000,size=10 大小为1010,
之后吧请求route到各个shard,每个shard同样创建这么个 priority queue,并把结果放到queue中,把queue返回给协调节点,此时
获取的是一些docid,这个时候mget去各个shard批量获取(若用_souce查询,那么可以直接把document返回)
协调节点吧所有的进行merger,符合要求的放到自己的queue,
并返回给客户端。
没from size jiushi 前10条
跳跃结果
因为给个shard 的存放数据可能排序不同,请求结果可能来自不同的shard,这样可能导致查询结果排序不同。解决方案是设置
preference为字符串,让每次查询都去制定的shard去搜索。
scoll 技术搜索大量数据
一次查询很大两数据性能会很慢,我们使用scoll技术,一批一批的查询,直到所有的数据处理完。
使用scoll数据会在第一次执行时候,建立一个视图快照,之后就基于这个视图快zhao提供数据搜索。
get /index/type/_search?scoll=1m
{
"query":{
“match_all”:{}
},
"sort":["_doc"],
"size":3
}
这批查询 返回3个结果集,返回一个scollid,
如何下一批查询呢
get /_search/scoll
{
scoll=1m,
"scoll_id":"shangmianfanhui de scollid"
}
创建索引
put /my_index
{
"setting":{
"number_of_shards":1,
"number_of_replicas":0
},
"mapping":{
"my_type":{
"my_feild":{
"type":"string"
}
}
}
}
修改索引
number_of_shard bu neng 修改 ,mapping 只能新增feild 不能修改feild
delete /my_index
定制自己的分词器
doc1:name age school sex
doc2:name age school birthday
子lunce底层是
{
ecommerce:{
mapping:{
_type:"string",
idnex:not
},
"name":{
type:string
},
"age":{
type:string
},
"school":{
type:string
},
"sex":{
type:string
},
"birthday":{
type:string
}
}
}
他把所有的type都存在一起。
最佳实践 把类似的type放到一个index 下 ,这些type 应该是有多个相同的feild
如把完全不同的type放到一个index下 在lunce中会有一半的field是空,严重的浪费空间,影响性能。