ES搜索引擎-简单⼊门
基本概念:
索引Index
es吧数据放到⼀个或者多个索引中,如果⽤关系型数据库模型对⽐,索引的地位与数据库实例(db)相当。索引存放和读取的基本单元是⽂档(document)。es内部使⽤的是apache lucene实现的索引中数据的读写。(es被视为单独的⼀个索引,在lucene中不⽌⼀个,因为分布式中,es会⽤到分区shards和备份 replicas机制讲⼀个索引存储多份)。
⽂档document
在es中,⽂档主要是存储实体。所有的es应⽤需求最后都需要统⼀建成⼀个检索模型:检索相关⽂档。
⽂档由⼀个或多个域,每个域field由⼀个域名或多个值组成(有多个值的称为多值域)。
在es中每个⽂档都可能会有不同的域field集合;也就是说⽂档是没有固定的模式和同意的结构的。⽂档之间保持的相似性即可。
在客户端⾓度来看,⽂档就是⼀个json对象。
参数映射 所有的⽂档在存储之前都必须分析(analyze)流程,⽤户可以配置输⼊⽂本分解成token的⽅式:哪些token呗滤掉;或者其它的处理流程,⽐如去除html标签。
⽂档类型(type)
每个⽂档在es中都必须设定它的类型。⽂档类型使得同⼀个索引中在存储结构不同⽂档时,只需根据⽂档类型就可以到对应的参数映射信息,⽅便⽂档的存取。
节点Node
单独es服务器实例成为⼀个节点。
集Cluster
集能够存储超出单机容量的信息。由于⽬前单点就可以满⾜咱们的需求,就不详细介绍了。
索引副本Replica
通过索引分⽚机制可以想es集中导⼊超过单机容量的数据,客户端操作任意⼀个节点接⼝实现
对集数据的读写。(不做详细解释了)
时间之门gateway
在运⾏的过程中,es会收到集的状态,索引的参数等信息。这些呗存储在gateway中。
es背后核⼼理念:
es是构造极少数的⼏个极少数的概念之上的。
开箱急⽤。
天⽣集。
⾃动容错。json值的类型有哪些
扩展性强。
es⼯作原理:
启动过程:
当es节点启动后,会利⽤多播(multicast)或单播(别问我什么是单播,多播,没必要纠结这些)寻病简历链接。如图:
在集中,⼀个节点呗选举成主节点。这个节点扶着管理集的状态,当集的拓展结构改变时把索引分区分派到相对性的节点上。
在⽤户⾓度看节点在es中并没有占据主要位置,这与其它系统是不同的(数据库系统)。实际上⽤户并不需要知道哪个节点是主节点;所有的操作需求可以发到任意节点,es内部完成这些⼯作。必要时任意节点都可以并发的把查询⾃居分发到其他节点,然后合并各个节点返回的查询结果。最后返回⽤户⼀个完整结果集。所有的这些⼯作不需要经过主节点转发(节点之前通过p2p的⽅式通讯)。
在必要时,会进⾏恢复⼯作。这时主节点会去检查哪些分⽚可⽤,决定⽤哪些分⽚。处理完后,集转⼊黄⾊状态。
这意味着集可以处理搜索请求了。但是还没有⽕⼒全开(这主要是由于所有的主索引分区都已经分配好了,但是索引副本还没有)。接下来就是到复制好的分区,病设置成索引副本。当⼀个分区数量太少时,主节点会界定将缺少的分区放到哪个节点中,并且依照主分区创建副本。所有⼯作完成后,集就会变成绿⾊状态(标⽰所有的主分区的索引副本都已经分配完成了)。
探测是吧节点
在正常⼯作时,主节点会监控所有节点,查看各个节点是否⼯作正常。如果在指定的时间⾥,节点⽆法访问,就呗视为出现故障了,接下来错误处理程序就会启动。集需要均衡——由于该节点出现故障,分配到该节点的索引分⽚丢失。其实节点上相应的分区就会吧⼯作接管过来的这个过程可以通过配置满⾜⽤户需求。
由于只是展⽰es的⼯作原理,就以下图三个节点的集为例。集中有⼀个主节点和两个数据节点。主节点想其他节点发送ping命令后等待回应。如果得到回应(实际上可能得不到恢复ping命令个数,取决于⽤户配置),改节点就会被移出集。
与es进⾏通讯
归根到底,最重要的是如何往es中添加数据以及如何查询数据。es提供了api,这些api都是基于rest风格。⽽且这些api⾮常容易与其他能够处理http的系统进⾏集。
es为数据应该伴随在url中,或作为请求主体requst body。以⼀种json格式的⽂档发送给服务器。
es内部,节点之间通讯解释⽤的先关javaapi。
重点来咯
索引数据
es提供了4中索引数据的⽅法。最简单的就是索引api。通过它可以将⽂档添加到指定的索引中去。⽐如curl⼯具。我可以通过如下命令创建⼀个新的⽂档
第2、3中⽅法,可以通过bulk API和UDP API批量添加⽂档。通常的bulk API采⽤HTTP协议,UDP bulk api采⽤⾮连接的数据包协议。UDP协议传输速度更快,但可靠性差点、最后⼀种是通过rivier插件。river运⾏在es集的节点上,能够从外部系统中获取数据。
有⼀点需要注意,索引数据的曹组只会发⽣在主分区上,⽽不会发⽣在分区副本上。如果索引数据的请求发送到节点上没有合适的分⽚或者分⽚副本,那么请求就会被转发到含有主分区的节点。
数据查询
查询api在es中有着很⼤的⽐重。通过query DSL(基于json,⽤于构造复杂的语⾔)
使⽤类型查询:简单关键词、短语、区间、布尔、模糊、跨度、通配符、地理位置等查询⽅式。
通过组合简单查询构造复杂的查询。
过滤⽂档,去除不符合标准的⽂档⽽且不影响打分排序。
查给定⽂档的相似⽂档。
查给定短语的搜索建议和查询短语修正。
通过faceting构建动态的导航和数据统计。
使⽤prospective search⽽且到匹配写定⽂档的查询语句(prospective search⼀种推送⽅式。⽤户的查询语句存储在索引中,如果新的⽂档添加到索引中,就把⽂档关联到匹配的查询语句中。这种适合于新闻,博客等定时更新的场景)。
关于数据查询,其核⼼在于查询过程不是⼀个简单、单⼀的流程。通过这个过程分为两个阶段:查询阶段和结果汇总阶段。在查询分发阶段,会从各个分⽀中查询数据;在结果汇总阶段,会从各个分上查询到结果进⾏合并,排序等其他处理过程,然后返回给⽤户。
⽤户可以通过指定搜索类型来控制查询的分发和汇总过程。
索引参数设置
es索引参数会⾃动配置
⽂档结构以及域类型会⾃动识别。当然es也允许⽤户⾃定修改默认配置。
⽐如,⾃⾏配置很多参数,⽐如通过mapping配置索引中的⽂档结构,设置分区shard和副本replica的个数,设置⽂本组件……
集管理和监控
通过管理和监控部分的api,⽤户可以更改集设置。⽐如调整节点发现机制或更改索引的分⽚策略。⽤户可以查看集状态信息,或者每个节点和索引和统计信息。集监控的api⾮常⼴泛。
强⼤的⽤户查询语⾔DSL
if/idf打分公式
这个就是打分公式的真⾯⽬。如果只是为了调整查询语句之间的关联关系,⽤户不必去理解它的原理。但只搜啊要知道它是如何⼯作的。
lucene概念上的打分公式
上⾯展⽰了布尔信息检索和向量空间信息检索模型的组合。(这个暂时忽略)
可以了解更多东西可以去这⾥
从es的⾓度看打分排序
最重要的是利⽤lucene构建起来的es允许⽤户修改默认的打分算法。但es不仅仅是lucene的简单封装,因为es中,⽂档排序并⾮完全依赖apache lucene的打分算法。es实现了多种不同的查询类型,这些查询类型可以完全依赖与⽂档的打分计算⽅式,es允许通过脚本定制⽂档的打分⽅式。
查询重写机制
如果你曾经使⽤过很多不同的查询类型,⽐如前缀查询和通配符查询,从本质上,任何的查询都可以视为对多个关键词查询。查询重写(query rewrite),es对⽤户查询进⾏了重写,这样做为了保证性能。重写过程是吧lucene⾓度认为原始的、开销⼤的查询对象转变成⼀系列开销⼩的查询对象的⼀个过程。
前缀查询:
例如:
我是知道所有字符以j开头的⽂档。这个需求⾮常简单,在client索引上运⾏
查询结果的重打分
有些场景对查询语句的结果⽂档进⾏重新打分是很有必要的。重新打分的原因可能各有相同。
其中⼀个原因可能是处于性能考虑,⽐如对整个有序的结果集进⾏重排序开销会很⼤,通常就会只对结果集进⾏重排序。
理解重打分
在es中,重打分是⼀个对限定数⽬的查询结果进⾏再次打分的⼀个过程。这意味着es会根据新的打分规则对结果的前n个⽂档重新进⾏⼀次排序
例
rescore query的结构:
重打分的参数
在查询语句的rescore对象中,⽤户可以添加如下参数
window_size提供了与N个⽂档的相关信息。⽤于执⾏分⽚上⽤于重打分的⽂档个数
query_weight默认1;原查询的打分会先乘以query_weight,然后与rescore的得分相加。
rescore_query_weight默认1,rescore的打分会先乘该值,在与原查询的得分相加。
rescore_mode默认tatal;在es0.90.0中引⼊⽤来指定重打分⽂档的打分⽅式。可选值:total,max,avg和multiply。
total:最终得分为原查询得分和rescore得分的和;
max,最终得分为原查询得分和rescore得分的最⼤值;
min,最终得分为原查询得分和rescore得分的最⼩值;
avg,最终得分为原查询得分和rescore得分的平均值;
multiply,两种查询的得分相乘。
例如设置recore_mode参数值为total,⽂档最终得分是
查询结果的排序
当给es发送查询命令时,返回的⽂档集合默认会按照计算出来的⽂档打分排序。这个通常是
⽤户希望的:结果集中的第⼀个⽂档就是查询命令想要的⽂档。然⽽,有事我们希望改变这种排序
。
update API
当往索引中添加新的⽂档到索引中时,底层的lucene⼯具包会分析每个域,⽣成token流
token流过滤后得到倒排索引。在这个过程中输⼊⽂版中⼀系诶不必要的信息会丢掉。
这些不必要的信息可能是⼀些特殊词的位置,⼀些停⽤的词或⽤同义词代替的词,或者词尾
。这也是为什么⽆法对lucene中的⽂档进⾏修改,每次修改⼀个⽂档时,必须吧⽂档所有域 添加到索引中。es通过_source这个代理域来存储或检索⽂档中的真是数据。
当我们想更新⽂档时,es会把数据放到_souce域中,然后做出修改,最后吧更新后的⽂档
添加到索引中。让然前提是_source域的这项特性必须⽣效。⽂档更新命令只能更新⼀个⽂档
查询命令的⽂档更新还没有出来。
更新:
使⽤update API创建或删除⽂档
update API不仅可以修改某个域,同时也能操作整个⽂档。
upsert特性使得在定位到⼀个不存在的⽂档是,它会被创建爱你出来:
如果⽂档存在,该命令将重置year域中的值;否则会被创建。新的⽂档包含upset中定义的titile域。当然,上⾯的命令还有可以使⽤脚本:
update还允许⽤户选择性的删除整个⽂档。
filters优化查询:
es⽀持多种类型的查询,但是查询那个匹配成功,哪个应该呈现给⽤户,查询并不是唯⼀的。es查询dsl允许⽤户使⽤绝⼤数查询都会有各⾃的标⽰。
过滤器(filters)和缓存
ES提供了特殊的缓存,filter cache来存储filters得到的结果集。此外,存储filters不需要太多的内存(它只保留⼀种信息,即哪些⽂档与filter相匹配),同时它可以与其他查询复⽤,极⼤的提⾼查询的性能。
例:
该命令查询得到满⾜如下条件的⽂档:name域值为joe同时值为1981。
⽤上⾯命令格式构建查询,查询对象会将所有的条件绑定到⼀起存储到缓存中;因此如果我们查询⼈名相同但出⽣年份不同的运动员,es⽆法重⽤上⾯查询命令中的任何信息。
因此,我们需要优化下查询。由于1千个⼈可能有⼀千个⼈名,所以⼈名不太适合缓存起来;但是年份⽐较适合。因此我们引⼊⼀个不同的查询命令,将⼀个简单的query与⼀个filter结合起来。
我们使⽤⼀个filtered类型的查询对象,查询对象将query元素与filter元素包含进去。第⼀次运⾏查询命令后,es会吧filter缓存起来,如果有查询⽤到⼀样的filter,就会直接⽤缓存。
并⾮所有的filters都会被默认缓存起来
实际上es不会缓存所有的filters。这是因为部分filters会⽤到域数据缓存(field date cache)。该缓存⼀般⽤于按域值排序和faceting操作场景中。默认情况,如下filters不会呗缓存:
尽管最后三种不会⽤到域缓存,它们主要⽤于控制filters,因此不会被缓存,但是它们控制的filters在⽤时都已经缓存好了。
更改es缓存⾏为
es允许⽤户通过_cache和_cache_key属性⾃⾏开启或关闭filters功能。
假设我们将关键词过滤器结果缓存起来,病给缓存项的key取名为year_1981_cache:
也可以⽤下⾯命令关闭过滤器缓存:
为了获取更多的控制权,我们需要给缓存项的key取名。
⽐如,有些查询复⽤机不多,我们希望指定定时清理这些查询的缓存。如果不指定_cache_key。就只能清除整个过滤器缓存filter cacahe;反之,只需执⾏如下命令:
关键词查过滤器
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论