ElasticSearch(简称ES)是一个开源的高扩展的分布式全文检索引擎;它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器;可以处理PB级别的数据。
是当前流行的企业级搜索引擎。
官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
参考:概述
连接es数据库:
curl -u admin:admin https://master:9200/
查询所有索引:
curl -u admin:admin 'https://master:9200/_cat/indices?v'
查询单个索引内容,如查询cqic_surf_chn_mul_yer索引库:
curl -u admin:admin https://master:9200/cqic_surf_chn_mul_yer/_search?pretty
根据条件查询:
curl -u admin:admin https://master:9200/bigdata/_search?q=name:hadoop&pretty
注意:高版本的es增加了安全机制,要求严格内容类型查询,所以在查询时需要加上请求头:-H "Content-Type: application/json"
返回结果是JSON格式;
其中最重要的是hits字段,默认包含所查询结果的前10个文档,且包含文档的_index、_type、_id、_source字段;
可以直接从返回结果中获得整个文档,而不像其他搜索引擎仅返回文档的ID,需要单独去获取文档。
_score衡量了文档与查询的匹配程度,返回文档按_score降序排列;
total字段表示匹配到的文档总数;
注:es查询结果上限1万条,如果需要查询数据超过1W,可以调整参数:max_result_window,或翻页查询,见下文。
DSL(domain specific language)查询语句的执行结果依赖于它们是用于查询语境还是过滤语境。
query的内容会自动进行分词拆分。
1、空查询
没有查询条件的查询,就是空查询,会匹配所有文档。
{"query": {}}
,等同于:{"query": {"match_all": {}}}
2、查询与过滤
DSL查询根据使用目的不同分为两种类型:查询(Query context);过滤(Filter context)
查询(Query):在上下文查询语境中,会询问文档与查询语句的匹配程度,判断文档是否匹配并计算相关性评分(_score)。
过滤(Filter):在上下文过滤语境中,主要解决文档是否匹配的问题,而不会在意匹配程度(相关性评分),过滤主要用于结构化数据。
一般来说,过滤语句比查询语句的执行效率高,因为它不用计算文档的相关性评分。频繁使用的过滤语句的结果集会被 ES自动缓存,以提高性能。过滤的目的就是粗暴地快速缩小匹配的结果集。通常全文搜索或需要用到相关性评分的场景采用查询(query),其他的全部用过滤(filter)。在进行搜索时,常会结合查询和过滤来达到我们的查询目的。
3、全文查询
说明 | |
---|---|
match | 关键字匹配查询,模糊查询,默认是逻辑或,可通过operator参数更改 |
term | 关键字匹配查询,精确查询 |
terms | 关键字匹配查询,多条件查询 match_all 无条件查询所有 |
range | 范围查询,gt大于;lt小于;gte大于或等于;lte小于或等于 |
bool | 复合查询,组合叶子查询或复合查询语句,如must, should, must_not |
must和should在上下文查询中执行;must_not在上下文过滤中执行
安装elasticsearch包,参考 官方文档
pip install elasticsearch
create 如果文档不存在就创建,但如果文档存在就返回错误
index 如果文档不存在就创建,如果文档存在就更新
update 更新一个文档,如果文档不存在就返回错误
delete 删除一个文档,如果文档id不存在就返回错误
其中index是比较常用的。还有bulk的操作,某一个操作失败,不会影响其他文档的操作,并会在返回结果中告诉你失败的详细原因。
如果插入数据信息有问题想修正,可以采用update方法
注意:更新数据时采用{“doc”:{“name”:“python1”,“addr”:“深圳1”}}字典模式,尤其是doc标识不能缺少。
删除数据比较简单,指定文档的索引、文档类型和文档ID即可。
游标查询(scroll查询):可以用于对ES有效地执行大批量的文档查询,而又不用付出深度分页那种代价。
多文档操作:multi_get 和 bulk,适合批量操作
注意:创建索引库和索引时,索引库名称必须全部小写,不能以下划线开头,不能含逗号;如果没有指定ID,es会自动生成随机ID
create(): index是索引名称, doc_type是文档类型, id是唯一标识ID, body是文档内容
index(): 与create()区别是不需要指定id,会自动生成一个id, create()方法其实是index()的封装
term query会去倒排索引中寻找确切的term,它并不知道分词器的存在。这种查询适合keyword 、numeric、date。
term:查询某个字段里含有某个关键词的文档
terms:查询某个字段里含有多个关键词的文档
a、term 和 terms 是 包含(contains) 操作,而非 等值(equals) (判断)
b、不知道分词器的存在,所以不会去分词,
bulk方法:
可以同时执行多个操作,但只请求一次,从而在批量操作时很大程度上减少程序系统开销。此外,bulk不仅可以批量执行插入或删除,还可以在一次请求中,既插入又删除或更新。 但要注意的是,任何一种操作都有固定的文档格式,只有完全符合该格式要求,才可执行成功。
es写入数据时有个刷新时间间隔默认1s,所以当时写入,要过一小会儿才能查询到
更多细节参考:
https://blog.csdn.net/sinat_38682860/article/details/107693969
https://blog.csdn.net/weixin_42182448/article/details/113655731
#http://www.cnblogs.com/letong/p/4749234.html
#http://elasticsearch-py.readthedocs.io/en/master/api.html#elasticsearch
#http://blog.csdn.net/xiaoxinwenziyao/article/details/49471977
#https://github.com/Parsely/pykafka
1、settings
主要用来配置索引的一些全局属性,比如分片数,副本数,刷新频次等。
number_of_shards:索引分片数量
索引分片数在索引创建好了之后就不能调整了,只能重建索引
number_of_replicas:控制索引的副本数量
index.refresh_interval:索引刷新频率
索引刷新频率:数据写入后几秒可以被搜索到,默认是 1s。每次索引的 refresh 会产生一个新的 lucene 段,这会导致频繁的合并行为,如果业务需求对实时性要求没那么高,可以将此参数调大。
2、mapping
定义文档及其包含的字段如何存储和索引。【详见下节】
每个文档都是字段的集合,每个字段都有自己的数据类型。 mapping属性主要用来设置索引中的字段名称和字段类型以及text字段的分词策略。
映射是定义一个文档及其所包含字段如何被存储和索引的方法。
mapping主要有2种类型:
1、动态映射(Dynamic Mapping)
写入文档时,索引不存在,会自动创建索引, 无需手动创建,ES会根据内容推断字段的类型,推断会不准确,可能造成某些功能无法使用,例如 范围查询。
2、精确映射 Explicit mapping
由用户自己定义索引的映射,这种方式会更加精准。
避免类型陷阱:
It is no longer possible to delete the mapping for a type. Instead you should delete the index and recreate it with the new mappings.
注意:
ES的mapping可以新增字段,但是对于已经存在的字段,只能添加属性,不能修改字段的类型。
如果需要修改已经存在的字段的type类型,只能进行重建索引reindex。
ES的mapping并不是不能修改,只是不能对已经存在的字段类型进行修改。
Elasticsearch底层使用的是lucene库,字段类型修改以后索引和搜索要涉及分词方式等操作,不允许修改类型在我看来是符合lucene机制的。
ES无法更改现有索引的数据结构;只能删除数据,不能删除数据结构;数据结构类型一旦定义,无法修改!
在一个关系型数据库中,表之间是相互独立的。一个表中的列与另一个表中同名的列没有关系。然而在映射类型中却不是这样的。
在一个Elasticsearch的索引中,有相同名称字段的不同映射类型在Lucene内部是由同一个字段支持的。这会导致一些问题,比如,当你希望在一个索引中的两个映射类型,一个映射类型中的 deleted 字段映射为一个日期数据类型的字段,而在另一个映射类型中的 deleted 字段映射为一个布尔数据类型的字段,这就会失败。最重要的是,在一个索引中存储那些有很少或没有相同字段的实体会导致稀疏数据,并且干扰Lucene有效压缩文档的能力。基于这些原因,我们决定从Elasticsearch中删除映射类型的概念。
es中的文档等价于java中的对象,是强数据类型。
用来索引长文本(如新闻正文、邮件内容等),在建立索引前会将这些文本进行分词,转化为词的组合,建立索引。允许es来检索这些词语。不能用来排序和聚合。
适合简短、结构化字符串,如email地址、手机号等,可以用于过滤、排序、聚合检索,也可以用于精确查询。不需要进行分词。keyword 类型字段只能用本身来进行检索。
数字类型分为 long、integer、short、byte、double、float、half_float、scaled_float。
数字类型的字段在满足需求的前提下应当尽量选择范围较小的数据类型,字段长度越短,搜索效率越高,对于浮点数,可以优先考虑使用 scaled_float 类型,该类型可以通过缩放因子来精确浮点数,例如 12.34 可以转换为 1234 来存储。
在 ES 中日期可以为以下形式:
1、格式化日期字符串,如 2020-03-17 00:00
、2020/03/17
2、时间戳(和 1970-01-01 00:00:00 UTC 的差值),单位毫秒或者秒
JSON 文档中同样存在布尔类型,不过 JSON 字符串类型也可以被 ES 转换为布尔类型存储,前提是字符串的取值为 true 或者 false,布尔类型常用于检索中的过滤条件。
参考:
关于数据类型和搜索的问题
修改索引字段类型的一种解决办法
解决自定义mapping的问题
出于可靠性、数据传输大小、服务器稳定性等等多方面的原因,es不接受一次性对数据库的所有内容进行遍历。es默认支持的查询数量是10,000。
要遍历所有查询结果,有三种方法:
1、分页循环遍历
2、scroll方法
scroll可以理解为一个游标或书签,当发起一个查询请求的时候,服务器会整理完全部的结果,但是这些结果不能一次性全部导出,只能分页导出,scroll就是这些页码的书签。
3、helpers.scan
返回数据对象迭代器,很大节省内存空间,查询速度要远远大于search。scroll进行数据分页,也可以返回大数据,但其返回的数据是以list的形式,如果一次需要返回的数据量比较大的话,则会十分耗费内存,而且数据传输速度也会比较慢。
当Elasticsearch响应请求时,它必须确定docs的顺序,全局排序响应结果。
如果请求的页数较少,假设每页10个docs,即pageSize=10,此时Elasticsearch不会有什么问题。
但若取的页数较大时(深分页),如请求第20页,Elasticsearch不得不取出所有分片上的第1页到第20页的所有docs,假设你有16个分片,则需要在coordinate node 汇总到 shards* (from+size)条记录,即需要 16*(20+10)记录后做一次全局排序,再最终取出 from后的size条结果作为最终的响应。 所以:当索引非常非常大(千万或亿),是无法按 from + size 做深分页的,分页越深则越容易OOM,即便不OOM,也是很消耗CPU和内存资源的。 游标查询允许我们 先做查询初始化,然后再批量地拉取结果。
这有点儿像传统数据库中的 cursor 。 游标查询会取某个时间点的快照数据。 查询初始化之后索引上的任何变化会被它忽略。
它通过保存旧的数据文件来实现这个特性,结果就像保留初始化时的索引 视图 一样。
深度分页的代价根源是结果集全局排序,如果去掉全局排序的特性的话查询结果的成本就会很低。 游标查询用字段 _doc 来排序。 这个指令让 Elasticsearch 仅仅从还有结果的分片返回下一批结果。
参考:
https://blog.csdn.net/a583929112/article/details/106363909
关于数据类型的设置:
https://blog.csdn.net/sinat_35930259/article/details/80354732
https://www.cnblogs.com/shoufeng/p/11266136.html
https://baijiahao.baidu.com/s?id=1661467987954314526&wfr=spider&for=pc