首页IT科技python es scan(Elasticsearch与Python的对接实现)

python es scan(Elasticsearch与Python的对接实现)

时间2025-04-30 15:15:36分类IT科技浏览6763
导读:什么是 Elasticsearch...

什么是 Elasticsearch

想查数据就免不了搜索            ,搜索就离不开搜索引擎                  ,百度            、谷歌都是一个非常庞大复杂的搜索引擎      ,他们几乎索引了互联网上开放的所有网页和数据            。然而对于我们自己的业务数据来说         ,肯定就没必要用这么复杂的技术了                  ,如果我们想实现自己的搜索引擎         ,方便存储和检索      ,Elasticsearch 就是不二选择                  ,它是一个全文搜索引擎            ,可以快速地储存                  、搜索和分析海量数据                  。

为什么要用 Elasticsearch

Elasticsearch 是一个开源的搜索引擎   ,建立在一个全文搜索引擎库 Apache Lucene™ 基础之上      。

那 Lucene 又是什么?Lucene 可能是目前存在的                  ,不论开源还是私有的               ,拥有最先进,高性能和全功能搜索引擎功能的库               ,但也仅仅只是一个库         。要用上 Lucene                  ,我们需要编写 Java 并引用 Lucene 包才可以   ,而且我们需要对信息检索有一定程度的理解才能明白 Lucene 是怎么工作的            ,反正用起来没那么简单                  。

那么为了解决这个问题                  ,Elasticsearch 就诞生了         。Elasticsearch 也是使用 Java 编写的      ,它的内部使用 Lucene 做索引与搜索         ,但是它的目标是使全文检索变得简单                  ,相当于 Lucene 的一层封装         ,它提供了一套简单一致的 RESTful API 来帮助我们实现存储和检索      。

所以 Elasticsearch 仅仅就是一个简易版的 Lucene 封装吗?那就大错特错了      ,Elasticsearch 不仅仅是 Lucene                  ,并且也不仅仅只是一个全文搜索引擎                  。 它可以被下面这样准确的形容:

·一个分布式的实时文档存储            ,每个字段可以被索引与搜索

·一个分布式实时分析搜索引擎

·能胜任上百个服务节点的扩展   ,并支持 PB 级别的结构化或者非结构化数据

总之                  ,是一个相当牛逼的搜索引擎               ,维基百科      、Stack Overflow         、GitHub 都纷纷采用它来做搜索            。

Elasticsearch 的安装

我们可以到 Elasticsearch 的官方网站下载 Elasticsearch:https://www.elastic.co/downloads/elasticsearch,同时官网也附有安装说明   。

首先把安装包下载下来并解压               ,然后运行 bin/elasticsearch(Mac 或 Linux)或者 bin\elasticsearch.bat (Windows) 即可启动 Elasticsearch 了                  。

我使用的是 Mac                  ,Mac 下个人推荐使用 Homebrew 安装:

brewinstallelasticsearch

Elasticsearch 默认会在 9200 端口上运行   ,我们打开浏览器访问

http://localhost:9200/ 就可以看到类似内容:

{ "name":"atntrTf", "cluster_name":"elasticsearch", "cluster_uuid":"e64hkjGtTp6_G2h1Xxdv5g", "version":{ "number":"6.2.4", "build_hash":"ccec39f", "build_date":"2018-04-12T20:37:28.497551Z", "build_snapshot":false, "lucene_version":"7.2.1", "minimum_wire_compatibility_version":"5.6.0", "minimum_index_compatibility_version":"5.0.0" }, "tagline":"YouKnow,forSearch" }

如果看到这个内容            ,就说明 Elasticsearch 安装并启动成功了                  ,这里显示我的 Elasticsearch 版本是 6.2.4 版本      ,版本很重要         ,以后安装一些插件都要做到版本对应才可以               。

接下来我们来了解一下 Elasticsearch 的基本概念以及和 Python 的对接。

Elasticsearch 相关概念

在 Elasticsearch 中有几个基本的概念                  ,如节点                  、索引         、文档等等         ,下面来分别说明一下      ,理解了这些概念对熟悉 Elasticsearch 是非常有帮助的               。

Node 和 Cluster

Elasticsearch 本质上是一个分布式数据库                  ,允许多台服务器协同工作            ,每台服务器可以运行多个 Elasticsearch 实例                  。

单个 Elasticsearch 实例称为一个节点(Node)   。一组节点构成一个集群(Cluster)            。

Index

Elasticsearch 会索引所有字段   ,经过处理后写入一个反向索引(Inverted Index)                  。查找数据的时候                  ,直接查找该索引      。

所以               ,Elasticsearch 数据管理的顶层单位就叫做 Index(索引),其实就相当于 MySQL      、MongoDB 等里面的数据库的概念         。另外值得注意的是               ,每个 Index (即数据库)的名字必须是小写                  。

Document

Index 里面单条的记录称为 Document(文档)         。许多条 Document 构成了一个 Index      。

Document 使用 JSON 格式表示                  ,下面是一个例子                  。

同一个 Index 里面的 Document   ,不要求有相同的结构(scheme)            ,但是最好保持相同                  ,这样有利于提高搜索效率            。

Type

Document 可以分组      ,比如 weather 这个 Index 里面         ,可以按城市分组(北京和上海)                  ,也可以按气候分组(晴天和雨天)   。这种分组就叫做 Type         ,它是虚拟的逻辑分组      ,用来过滤 Document                  ,类似 MySQL 中的数据表            ,MongoDB 中的 Collection                  。

不同的 Type 应该有相似的结构(Schema)   ,举例来说                  ,id 字段不能在这个组是字符串               ,在另一个组是数值               。这是与关系型数据库的表的一个区别。性质完全不同的数据(比如 products 和 logs)应该存成两个 Index,而不是一个 Index 里面的两个 Type(虽然可以做到)               。

根据规划               ,Elastic 6.x 版只允许每个 Index 包含一个 Type                  ,7.x 版将会彻底移除 Type                  。

Fields

即字段   ,每个 Document 都类似一个 JSON 结构            ,它包含了许多字段                  ,每个字段都有其对应的值      ,多个字段组成了一个 Document         ,其实就可以类比 MySQL 数据表中的字段   。

在 Elasticsearch 中                  ,文档归属于一种类型(Type)         ,而这些类型存在于索引(Index)中      ,我们可以画一些简单的对比图来类比传统关系型数据库:

RelationalDB->Databases->Tables->Rows->Columns Elasticsearch->Indices->Types->Documents->Fields

以上就是 Elasticsearch 里面的一些基本概念                  ,通过和关系性数据库的对比更加有助于理解            。

Python 对接 Elasticsearch

Elasticsearch 实际上提供了一系列 Restful API 来进行存取和查询操作            ,我们可以使用 curl 等命令来进行操作   ,但毕竟命令行模式没那么方便                  ,所以这里我们就直接介绍利用 Python 来对接 Elasticsearch 的相关方法                  。

Python 中对接 Elasticsearch 使用的就是一个同名的库               ,安装方式非常简单:

pip3installelasticsearch

官方文档是:https://elasticsearch-py.readthedocs.io/,所有的用法都可以在里面查到               ,文章后面的内容也是基于官方文档来的      。

创建 Index

我们先来看下怎样创建一个索引(Index)                  ,这里我们创建一个名为 news 的索引:

fromelasticsearchimportElasticsearch es=Elasticsearch() result=es.indices.create(index=news,ignore=400) print(result)

如果创建成功   ,会返回如下结果:

{acknowledged:True,shards_acknowledged:True,index:news}

返回结果是 JSON 格式            ,其中的 acknowledged 字段表示创建操作执行成功         。

但这时如果我们再把代码执行一次的话                  ,就会返回如下结果:

{error:{root_cause:[{type:resource_already_exists_exception,reason:index[news/QM6yz2W8QE-bflKhc5oThw] alreadyexists,index_uuid:QM6yz2W8QE-bflKhc5oThw,index:news}],type:resource_already_exists_ exception,reason:index[news/QM6yz2W8QE-bflKhc5oThw]alreadyexists,index_uuid:QM6yz2W8QE-bflKhc5oThw, index:news},status:400}

它提示创建失败      ,status 状态码是 400         ,错误原因是 Index 已经存在了                  。

注意这里我们的代码里面使用了 ignore 参数为 400                  ,这说明如果返回结果是 400 的话         ,就忽略这个错误不会报错      ,程序不会执行抛出异常         。

假如我们不加 ignore 这个参数的话:

es=Elasticsearch() result=es.indices.create(index=news) print(result)

再次执行就会报错了:

raiseHTTP_EXCEPTIONS.get(status_code,TransportError)(status_code,error_message,additional_info) elasticsearch.exceptions.RequestError:TransportError(400,resource_already_exists_exception,index [news/QM6yz2W8QE-bflKhc5oThw]alreadyexists)

这样程序的执行就会出现问题                  ,所以说            ,我们需要善用 ignore 参数   ,把一些意外情况排除                  ,这样可以保证程序的正常执行而不会中断      。

删除 Index

删除 Index 也是类似的               ,代码如下:

fromelasticsearchimportElasticsearch es=Elasticsearch() result=es.indices.delete(index=news,ignore=[400,404]) print(result)

这里也是使用了 ignore 参数,来忽略 Index 不存在而删除失败导致程序中断的问题                  。

如果删除成功               ,会输出如下结果:

{acknowledged:True}

如果 Index 已经被删除                  ,再执行删除则会输出如下结果:

{error:{root_cause:[{type:index_not_found_exception,reason:nosuchindex,resource.type: index_or_alias,resource.id:news,index_uuid:_na_,index:news}],type:index_not_found_exception, reason:nosuchindex,resource.type:index_or_alias,resource.id:news,index_uuid:_na_,index: news},status:404}

这个结果表明当前 Index 不存在   ,删除失败            ,返回的结果同样是 JSON                  ,状态码是 400      ,但是由于我们添加了 ignore 参数         ,忽略了 400 状态码                  ,因此程序正常执行输出 JSON 结果         ,而不是抛出异常            。

插入数据

Elasticsearch 就像 MongoDB 一样      ,在插入数据的时候可以直接插入结构化字典数据                  ,插入数据可以调用 create() 方法            ,例如这里我们插入一条新闻数据:

fromelasticsearchimportElasticsearch es=Elasticsearch() es.indices.create(index=news,ignore=400) data={title:美国留给伊拉克的是个烂摊子吗,url:http://view.news.qq.com/zt2011/usa_iraq/index.htm} result=es.create(index=news,doc_type=politics,id=1,body=data) print(result)

这里我们首先声明了一条新闻数据   ,包括标题和链接                  ,然后通过调用 create() 方法插入了这条数据               ,在调用 create() 方法时,我们传入了四个参数               ,index 参数代表了索引名称                  ,doc_type 代表了文档类型   ,body 则代表了文档具体内容            ,id 则是数据的唯一标识 ID   。

运行结果如下:

{_index:news,_type:politics,_id:1,_version:1,result:created,_shards:{total:2, successful:1,failed:0},_seq_no:0,_primary_term:1}

结果中 result 字段为 created                  ,代表该数据插入成功                  。

另外其实我们也可以使用 index() 方法来插入数据      ,但与 create() 不同的是         ,create() 方法需要我们指定 id 字段来唯一标识该条数据                  ,而 index() 方法则不需要         ,如果不指定 id      ,会自动生成一个 id                  ,调用 index() 方法的写法如下:

es.index(index=news,doc_type=politics,body=data)

create() 方法内部其实也是调用了 index() 方法            ,是对 index() 方法的封装               。

更新数据

更新数据也非常简单   ,我们同样需要指定数据的 id 和内容                  ,调用 update() 方法即可               ,代码如下:

fromelasticsearchimportElasticsearch es=Elasticsearch() data={ title:美国留给伊拉克的是个烂摊子吗, url:http://view.news.qq.com/zt2011/usa_iraq/index.htm, date:2011-12-16 } result=es.update(index=news,doc_type=politics,body=data,id=1) print(result)

这里我们为数据增加了一个日期字段,然后调用了 update() 方法               ,结果如下:

{_index:news,_type:politics,_id:1,_version:2,result:updated,_shards:{total:2, successful:1,failed:0},_seq_no:1,_primary_term:1}

可以看到返回结果中                  ,result 字段为 updated   ,即表示更新成功            ,另外我们还注意到有一个字段 _version                  ,这代表更新后的版本号数      ,2 代表这是第二个版本         ,因为之前已经插入过一次数据                  ,所以第一次插入的数据是版本 1         ,可以参见上例的运行结果      ,这次更新之后版本号就变成了 2                  ,以后每更新一次            ,版本号都会加 1。

另外更新操作其实利用 index() 方法同样可以做到   ,写法如下:

es.index(index=news,doc_type=politics,body=data,id=1)

可以看到                  ,index() 方法可以代替我们完成两个操作               ,如果数据不存在,那就执行插入操作               ,如果已经存在                  ,那就执行更新操作   ,非常方便               。

删除数据

如果想删除一条数据可以调用 delete() 方法            ,指定需要删除的数据 id 即可                  ,写法如下:

fromelasticsearchimportElasticsearch es=Elasticsearch() result=es.delete(index=news,doc_type=politics,id=1) print(result)

运行结果如下:

{_index:news,_type:politics,_id:1,_version:3,result:deleted,_shards:{total:2, successful:1,failed:0},_seq_no:2,_primary_term:1}

可以看到运行结果中 result 字段为 deleted      ,代表删除成功         ,_version 变成了 3                  ,又增加了 1                  。

查询数据

上面的几个操作都是非常简单的操作         ,普通的数据库如 MongoDB 都是可以完成的      ,看起来并没有什么了不起的                  ,Elasticsearch 更特殊的地方在于其异常强大的检索功能   。

对于中文来说            ,我们需要安装一个分词插件   ,这里使用的是 elasticsearch-analysis-ik                  ,GitHub 链接为:https://github.com/medcl/elasticsearch-analysis-ik               ,这里我们使用 Elasticsearch 的另一个命令行工具 elasticsearch-plugin 来安装,这里安装的版本是 6.2.4               ,请确保和 Elasticsearch 的版本对应起来                  ,命令如下:

elasticsearch-plugininstallhttps://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.2.4 /elasticsearch-analysis-ik-6.2.4.zip

这里的版本号请替换成你的 Elasticsearch 的版本号            。

安装之后重新启动 Elasticsearch 就可以了   ,它会自动加载安装好的插件                  。

首先我们新建一个索引并指定需要分词的字段            ,代码如下:

fromelasticsearchimportElasticsearch es=Elasticsearch() mapping={ properties:{ title:{ type:text, analyzer:ik_max_word, search_analyzer:ik_max_word } } } es.indices.delete(index=news,ignore=[400,404]) es.indices.create(index=news,ignore=400) result=es.indices.put_mapping(index=news,doc_type=politics,body=mapping) print(result)

这里我们先将之前的索引删除了                  ,然后新建了一个索引      ,然后更新了它的 mapping 信息         ,mapping 信息中指定了分词的字段                  ,指定了字段的类型 type 为 text         ,分词器 analyzer 和 搜索分词器 search_analyzer 为 ik_max_word      ,即使用我们刚才安装的中文分词插件      。如果不指定的话则使用默认的英文分词器         。

接下来我们插入几条新的数据:

datas=[ { title:美国留给伊拉克的是个烂摊子吗, url:http://view.news.qq.com/zt2011/usa_iraq/index.htm, date:2011-12-16 }, { title:公安部:各地校车将享最高路权, url:http://www.chinanews.com/gn/2011/12-16/3536077.shtml, date:2011-12-16 }, { title:中韩渔警冲突调查:韩警平均每天扣1艘中国渔船, url:https://news.qq.com/a/20111216/001044.htm, date:2011-12-17 }, { title:中国驻洛杉矶领事馆遭亚裔男子枪击嫌犯已自首, url:http://news.ifeng.com/world/detail_2011_12/16/11372558_0.shtml, date:2011-12-18 } ] fordataindatas: es.index(index=news,doc_type=politics,body=data)

这里我们指定了四条数据                  ,都带有 title                  、url            、date 字段            ,然后通过 index() 方法将其插入 Elasticsearch 中   ,索引名称为 news                  ,类型为 politics                  。

接下来我们根据关键词查询一下相关内容:

result=es.search(index=news,doc_type=politics) print(result)

可以看到查询出了所有插入的四条数据:

{ "took":0, "timed_out":false, "_shards":{ "total":5, "successful":5, "skipped":0, "failed":0 }, "hits":{ "total":4, "max_score":1.0, "hits":[ { "_index":"news", "_type":"politics", "_id":"c05G9mQBD9BuE5fdHOUT", "_score":1.0, "_source":{ "title":"美国留给伊拉克的是个烂摊子吗", "url":"http://view.news.qq.com/zt2011/usa_iraq/index.htm", "date":"2011-12-16" } }, { "_index":"news", "_type":"politics", "_id":"dk5G9mQBD9BuE5fdHOUm", "_score":1.0, "_source":{ "title":"中国驻洛杉矶领事馆遭亚裔男子枪击               ,嫌犯已自首", "url":"http://news.ifeng.com/world/detail_2011_12/16/11372558_0.shtml", "date":"2011-12-18" } }, { "_index":"news", "_type":"politics", "_id":"dU5G9mQBD9BuE5fdHOUj", "_score":1.0, "_source":{ "title":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船", "url":"https://news.qq.com/a/20111216/001044.htm", "date":"2011-12-17" } }, { "_index":"news", "_type":"politics", "_id":"dE5G9mQBD9BuE5fdHOUf", "_score":1.0, "_source":{ "title":"公安部:各地校车将享最高路权", "url":"http://www.chinanews.com/gn/2011/12-16/3536077.shtml", "date":"2011-12-16" } } ] } }

可以看到返回结果会出现在 hits 字段里面,然后其中有 total 字段标明了查询的结果条目数               ,还有 max_score 代表了匹配分数         。

另外我们还可以进行全文检索                  ,这才是体现 Elasticsearch 搜索引擎特性的地方:

dsl={ query:{ match:{ title:中国领事馆 } } } es=Elasticsearch() result=es.search(index=news,doc_type=politics,body=dsl) print(json.dumps(result,indent=2,ensure_ascii=False))

这里我们使用 Elasticsearch 支持的 DSL 语句来进行查询   ,使用 match 指定全文检索            ,检索的字段是 title                  ,内容是“中国领事馆            ”      ,搜索结果如下:

{ "took":1, "timed_out":false, "_shards":{ "total":5, "successful":5, "skipped":0, "failed":0 }, "hits":{ "total":2, "max_score":2.546152, "hits":[ { "_index":"news", "_type":"politics", "_id":"dk5G9mQBD9BuE5fdHOUm", "_score":2.546152, "_source":{ "title":"中国驻洛杉矶领事馆遭亚裔男子枪击         ,嫌犯已自首", "url":"http://news.ifeng.com/world/detail_2011_12/16/11372558_0.shtml", "date":"2011-12-18" } }, { "_index":"news", "_type":"politics", "_id":"dU5G9mQBD9BuE5fdHOUj", "_score":0.2876821, "_source":{ "title":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船", "url":"https://news.qq.com/a/20111216/001044.htm", "date":"2011-12-17" } } ] } }

这里我们看到匹配的结果有两条                  ,第一条的分数为 2.54         ,第二条的分数为 0.28      ,这是因为第一条匹配的数据中含有“中国                  ”和“领事馆      ”两个词                  ,第二条匹配的数据中不包含“领事馆         ”            ,但是包含了“中国                  ”这个词   ,所以也被检索出来了                  ,但是分数比较低      。

因此可以看出               ,检索时会对对应的字段全文检索,结果还会按照检索关键词的相关性进行排序               ,这就是一个基本的搜索引擎雏形                  。

另外 Elasticsearch 还支持非常多的查询方式                  ,详情可以参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl.html

以上便是对 Elasticsearch 的基本介绍以及 Python 操作 Elasticsearch 的基本用法   ,但这仅仅是 Elasticsearch 的基本功能            ,它还有更多强大的功能等待着我们的探索                  ,后面会继续更新      ,敬请期待            。

本节代码:https://github.com/Germey/ElasticSearch   。

资料推荐

另外推荐几个不错的学习站点:

Elasticsearch 权威指南:https://es.xiaoleilu.com/index.html

全文搜索引擎 Elasticsearch 入门教程:http://www.ruanyifeng.com/blog/2017/08/elasticsearch.html

Elastic 中文社区:https://www.elasticsearch.cn/

参考资料

https://es.xiaoleilu.com/index.html

https://blog.csdn.net/y472360651/article/details/76468327

https://elasticsearch-py.readthedocs.io/en/master/

https://es.xiaoleilu.com/010_Intro/10_Installing_ES.html

https://github.com/medcl/elasticsearch-analysis-ik

python学习网         ,免费的在线学习python平台                  ,欢迎关注!

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
java中lambda表达式做什么的(Java的Lambda表达式到底是啥?) 网络多元化没有达到深刻性的例子(网络多元化的劣势)