赞
踩
首先存入的数据按index(必须小写)分为不同的文件,type代表了数据的类型方便读写,_id是唯一的,object可以是json。
基本概念可以看下链接2
一般的es会为每个filed建立倒排索引,记录值所在的term id,值叫做term,对应的id列表叫做 Posting List。
es为了提高搜索效率,对term进行排序,查找是二分查找提高了速度,这是 Term Dictionary,
现在再看起来,似乎和传统数据库通过B-Tree的方式类似啊,为什么说比B-Tree的查询快呢?B-Tree通过减少磁盘寻道次数来提高查询性能,Elasticsearch也是采用同样的思路,直接通过内存查找term,不读磁盘,但是如果term太多,term dictionary也会很大,放内存不现实,于是有了Term Index,就像字典里的索引页一样,A开头的有哪些term,分别在哪页,可以理解为前缀树
所以给定查询过滤条件 age=18 的过程就是先从 term index 找到 18 在 term dictionary 的大概位置,然后再从 term dictionary 里精确地找到 18 这个 term,然后得到一个 posting list 或者一个指向 posting list 位置的指针。然后再查询 gender= 女 的过程也是类似的。最后得出 age=18 AND gender= 女 就是把两个 posting list 做一个“与”的合并。
这个理论上的“与”合并的操作可不容易。对于 mysql 来说,如果你给 age 和 gender 两个字段都建立了索引,查询的时候只会选择其中最 selective 的来用,然后另外一个条件是在遍历行的过程中在内存中计算之后过滤掉。那么要如何才能联合使用两个索引呢?有两种办法:
PostgreSQL 从 8.4 版本开始支持通过 bitmap 联合使用两个索引,就是利用了 bitset 数据结构来做到的。当然一些商业的关系型数据库也支持类似的联合索引的功能。Elasticsearch 支持以上两种的联合索引方式,如果查询的 filter 缓存到了内存中(以 bitset 的形式),那么合并就是两个 bitset 的 AND。如果查询的 filter 没有缓存,那么就用 skip list 的方式去遍历两个 on disk 的 posting list。
关于skip list 和 bitset 请参考 https://www.infoq.cn/article/database-timestamp-02/?utm_source=infoq&utm_medium=related_content_link&utm_campaign=relatedContent_articles_clk
Single document APIs
Multi-document APIs
更过查询语法可查看文档 https://www.elastic.co/guide/en/elasticsearch/reference/5.6/docs-reindex.html
elastic权威指南翻译版 https://es.xiaoleilu.com/index.html
这是一个分页查询带排序的例子:
GET _index/_type/_search { "from": 0, "size": 20, "query": { "bool": { "must": [{ "match": { "FILED": "2019-06-28" } }, { "match_phrase": { "FILED": "TEXT VAIL" } }] } }, " _source":["filed1","filed2"], //指定返回的字段 不指定返回所有 "sort": [ { "FILED": { "order": "asc" } } ] }
Query查询上下文:
在查询上下文中,查询会回答这个问题——“这个文档匹不匹配这个查询,它的相关度高么?”
如何验证匹配很好理解,如何计算相关度呢?之前说过,ES中索引的数据都会存储一个_score分值,分值越高就代表越匹配。另外关于某个搜索的分值计算还是很复杂的,因此也需要一定的时间。
查询上下文 是在 使用query进行查询时的执行环境,比如使用search的时候。
Filter过滤器上下文:
在过滤器上下文中,查询会回答这个问题——“这个文档匹不匹配?”
答案很简单,是或者不是。它不会去计算任何分值,也不会关心返回的排序问题,因此效率会高一点。
过滤上下文 是在使用filter参数时候的执行环境,比如在bool查询中使用Must_not或者filter。
另外,经常使用过滤器,ES会自动的缓存过滤器的内容,这对于查询来说,会提高很多性能。
总结
查询上下文中,查询操作不仅仅会进行查询,还会计算分值,用于确定相关度;在过滤器上下文中,查询操作仅判断是否满足查询条件
过滤器上下文中,查询的结果可以被缓存。
Bool查询现在包括四种子句,must,filter,should,must_not。
{ "bool" : { "must" : { "term" : { "user" : "kimchy" } }, "filter": { "term" : { "tag" : "tech" } }, "must_not" : { "range" : { "age" : { "from" : 10, "to" : 20 } } }, "should" : [ { "term" : { "tag" : "wow" } }, { "term" : { "tag" : "elasticsearch" } } ], "minimum_should_match" : 1, "boost" : 1.0 } }
当我们不关心检索词频率TF(Term Frequency)对搜索结果排序的影响时,可以使用constant_score将查询语句query或者过滤语句filter包装起来。
检索词频率(TF):检索词在该字段出现的频率。出现频率越高,相关性也越高。字段中出现过5次要比只出现过1次的相关性高。
反向文档频率(IDF):每个检索词在索引中出现的频率。频率越高,相关性越低。 检索词出现在多数文档中会比出现在少数文档中的权重更低, 即检验一个检索词在文档中的普遍重要性。
权重 - score受到协调因子boost的影响 score = score + boost
在使用搜索“has-child”搜索父文档时,一般情况只返回子文档符合条件的父文档。用 Inner-hits 则可以把父子文档同时返回——既返回父文档,也返回匹配has-child条件的子文档,相当于在父子之间join了。
When set to true the ignore_unmapped option will ignore an unmapped field and will not match any documents for this query. This can be useful when querying multiple indexes which might have different mappings. When set to false (the default value) the query will throw an exception if the field is not mapped. – Docs
当你把ignore_unmapped 设置为true时,会忽略掉没有匹配上的字段并且当前的query不会返回任何documents,再查询多个索引时可能会有多个结果时候比较有用,如果设置为false,没有匹配时会抛出异常。默认false。
term query不会分词,是精确查询。
boolQuery: must:相当于sql的and must not:相当于sql的not should:相当于sql的or mathcquery:单个匹配 mathcAllQuery:匹配所有 termQuery:termQuery("key", obj) 完全匹配 ;termsQuery("key", obj1, obj2..) 一次匹配多个值 multiMatchQuery:multiMatchQuery("text", "field1", "field2"..); 匹配多个字段, field有通配符忒行 idsQuery:构造一个只会匹配的特定数据 id 的查询 constantScoreQuery:看了一下这个类的构造函数ConstantScoreQuery(Filter filter) ,我的理解就是通过构造filter来完成文档的过滤,并且返回一个复合当前过滤条件的文档的常量分数,这个分数等于为查询条件设置的boost fuzzyQuery:模糊查询 moreLikeThisQuery:文档中的文本查询 prefixQuery:前缀查询 rangeQuery:在一个范围内查询相匹配的文档 termQuery:一个查询相匹配的文件包含一个术语 termsQuery:一个查询相匹配的多个value---minimumMatch(1); // 设置最小数量的匹配提供了条件。默认为1。 wildcardQuery:通配符查询 nestedQuery:嵌套查询---scoreMode("total");// max, total, avg or none disMaxQuery:对子查询的结果做union, score沿用子查询score的最大值, spanFirstQuery:跨度查询,还包括(spanNearQuery,spanNotQuery,spanOrQuery,spanTermQuery)
如果需要分批管理数据,比如日志多久删除一次,可以使用别名,建立新的索引关联到原有的索引上,并不对更新这个别名关系,旧的索引就可以在合适的时机删除.
先创建新的索引,在执行别名设置。移除旧的别名并添加新的别名。
PUT logofesjson_v2 { "mappings": { "log_of_es_json": { "properties": { "logId": { "type": "long" }, "requestJson": { "type": "text", "index": false }, "responseJson": { "type": "text", "index": false } } } }, "index": { "number_of_shards": "5", "number_of_replicas": "1" } } POST _aliases { "actions": [ { "remove": { "index": "logofesjson_v1", "alias": "logofesjson" } }, { "add": { "index": "logofesjson_v2", "alias": "logofesjson" } } ] }
关于分片 https://blog.csdn.net/alan_liuyue/article/details/79585345
Elasticsearch为了实现分布式,引入了shard,将segment分布在不同的机器上。并且根据_routing来决定如何分配到指定的shard。
Elasticsearch中每个index由多个shard组成,默认是5个,每个shard分布在不同的机器上。shard分为主分片和副本分片,在文档写入时,会根据_routing来计算(OperationRouting类)得出文档要写入哪个分片。这里的写入请求只会写主分片,当主分片写入成功后,会同时把写入请求发送给所有的副本分片,当副本分片写入成功后,会传回返回信息给主分片,主分片得到所有副本分片的返回信息后,再返回给客户端。
在写入时,我们可以在Request自己指定_routing,也可以在Mapping指定文档中的Field值作为_routing。如果没有指定_routing,则会把_id作为_routing进行计算。由于写入时,具有相同_routing的文档一定会分配在同一个分片上,所以如果是自定义的_routing,在查询时,一定要指定_routing进行查询,否则是查询不到文档的。这并不是局限性,恰恰相反,指定_routing的查询,性能上会好很多,因为指定_routing意味着直接去存储数据的shard上搜索,而不会搜索所有shard。
从上述可以看出,Elasticsearch文档写入主要是写主分片和写副本分片。所以副本分片的个数就直接决定了写入的性能。合理配置副本数,在性能和安全之间取得平衡。
elastic实战系列 https://blog.csdn.net/xiaoyu_bd/article/details/81950081
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。