首页IT科技python操作elasticsearch(Elasticsearch基本介绍及其与Python的对接实现)

python操作elasticsearch(Elasticsearch基本介绍及其与Python的对接实现)

时间2025-08-03 04:05:54分类IT科技浏览4364
导读:什么是 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 安装:

brew install elasticsearch

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)中      ,我们可以画一些简单的对比图来类比传统关系型数据库:

Relational DB -> Databases -> Tables -> Rows -> Columns

Elasticsearch -> Indices -> Types -> Documents -> Fields

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

Python 对接 Elasticsearch

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

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

pip3 install elasticsearch

官方文档是: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] already exists, index_uuid: QM6yz2W8QE-bflKhc5oThw, index: news}], type: resource_already_exists_exception, reason: index [news/QM6yz2W8QE-bflKhc5oThw] already exists, 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

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

展开全文READ MORE
openlayer是什么(Openlayers 快速上手教程) bios里没有usb选项(bios没有usb启动项如何是好?bios设置usb启动项的方法图文教程)