知行编程网知行编程网  2022-10-12 13:30 知行编程网 隐藏边栏  9 
文章评分 0 次,平均分 0.0
导语: 本文主要介绍了关于Elasticsearch基本介绍及其与Python的对接实现的相关知识,包括做对接是什么意思,以及信息对接和整合这些编程知识,希望对大家有参考作用。


什么是 Elasticsearch

要想查资料,就离不开搜索,而搜索又离不开搜索引擎。百度和谷歌都是非常庞大和复杂的搜索引擎。它们索引几乎所有在 Internet 上打开的网页和数据。但是,对于我们自己的业务数据,绝对没有必要使用这么复杂的技术。如果我们想实现自己的搜索引擎以便于存储和检索,Elasticsearch 是最好的选择。它是一个可以快速存储、搜索和分析海量数据的全文搜索引擎。


为什么要用 Elasticsearch

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

那么什么是Lucene? Lucene 可能是现有的最先进、高性能和全功能的搜索引擎库,无论是开源的还是私有的,但它只是一个库。要使用Lucene,我们需要编写Java并引用Lucene包,并且需要对信息检索有一定的了解才能理解Lucene是如何工作的,反正使用起来也不是那么简单。

于是为了解决这个问题,Elasticsearch 应运而生。 Elasticsearch 也是用 Java 编写的。它在内部使用Lucene进行索引和搜索,但它的目标是让全文检索变得简单,相当于对Lucene进行了一层封装。它提供了一组简单一致的 RESTful API 来帮助我们实现存储和检索。

那么 Elasticsearch 只是一个简单的 Lucene 包装器吗?这是一个很大的错误,Elasticsearch 不仅仅是 Lucene,它也不仅仅是一个全文搜索引擎。可以准确地描述如下:

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

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

可扩展数百个服务节点,支持PB级结构化或非结构化数据

简而言之,它是一个非常强大的搜索引擎。 Wikipedia、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" : "You Know, for Search"
}

如果看到这个内容,说明Elasticsearch已经安装启动成功。它显示我的 Elasticsearch 版本是 6.2.4 版本。版本非常重要。安装一些插件后,版本必须对应。

接下来,我们来看看Elasticsearch的基本概念以及与Python的联系。


Elasticsearch 相关概念

Elasticsearch中有几个基本概念,比如节点、索引、文档等,我们分别解释一下。了解这些概念对于熟悉 Elasticsearch 非常有帮助。


Node 和 Cluster

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

单个 Elasticsearch 实例称为节点。一组节点形成一个集群。


Index

Elasticsearch 索引所有字段并在处理后将它们写入倒排索引。查找数据时,直接查找索引。

因此,Elasticsearch 数据管理的顶层单元称为 Index,实际上相当于 MySQL、MongoDB 等中数据库的概念。另外值得注意的是,每个 Index(即数据库)的名称必须小写。


Document

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

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

同一个Index中的文档不需要相同的方案,但最好保持相同,这样有助于提高搜索效率。


Type

可以对文档进行分组。例如,在天气指数中,它们可以按城市(北京和上海)或气候(晴天和雨天)分组。这种分组称为Type,是一种用于过滤Documents的虚拟逻辑分组,类似于MySQL中的数据表和MongoDB中的Collections。

不同的类型应该有相似的模式,例如,id 字段不能是一个组中的字符串而另一个组中的值。这是与关系数据库表的区别。具有完全不同属性的数据(例如产品和日志)应该存储为两个索引,而不是一个索引中的两个类型(尽管可以这样做)。

按照计划,Elastic 6.x 版本只允许每个 Index 包含一个 Type,7.x 版本将彻底移除 Type。


Fields

也就是字段,每个文档类似于一个JSON结构,它包含很多字段,每个字段都有对应的值,多个字段组成一个文档,其实可以比作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的索引:

from elasticsearch import Elasticsearch
es = Elasticsearch()
result = es.indices.create(index='news', ignore=400)
print(result)

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

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

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

但如果此时我们再次执行代码,会返回如下结果:

{'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}

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

注意我们代码中使用的ignore参数是400,也就是说如果返回结果是400,这个错误会被忽略不报错,程序也不会抛出异常。

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

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

再次执行就会报错了:

raise HTTP_EXCEPTIONS.get(status_code, TransportError)(status_code, error_message, additional_info)
elasticsearch.exceptions.RequestError: TransportError(400, 'resource_already_exists_exception', 'index [news/QM6yz2W8QE-bflKhc5oThw] already exists')

这样,程序的执行就会出现问题。因此,我们需要利用好ignore参数来排除一些意外情况,从而保证程序的正常执行不被中断。


删除 Index

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

from elasticsearch import Elasticsearch
es = Elasticsearch()
result = es.indices.delete(index='news', ignore=[400, 404])
print(result)

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

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

{'acknowledged': True}

如果索引已经被删除,再次执行删除会输出如下结果:

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

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


插入数据

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

from elasticsearch import Elasticsearch
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()方法。代码如下:

from elasticsearch import Elasticsearch
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字段,即表示更新成功。另外,我们还注意到有一个字段_version,表示更新的版本号,2表示这是第二个版本,因为之前已经插入过。数据已经传过一次,所以第一次插入的数据是版本1。可以参考上面例子的运行结果。本次更新后,版本号变为2。每次更新后,版本号会增加1。

另外,也可以使用index()方法进行更新操作,写法如下:

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

可以看出 index() 方法可以代表我们执行两个操作。如果数据不存在,则执行插入操作,如果已存在,则执行更新操作,非常方便。


删除数据

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

from elasticsearch import Elasticsearch
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字段被删除了,说明删除成功,_version变成3,加1。


查询数据

以上操作都是非常简单的操作,MongoDB等普通数据库都可以完成。这似乎不太好。 Elasticsearch 比较特别的地方在于其极其强大的检索功能。

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

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

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

安装后重启 Elasticsearch,它会自动加载已安装的插件。

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

from elasticsearch import Elasticsearch
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)

这里我们先删除之前的索引,然后新建一个索引,然后更新它的映射信息。映射信息指定分词的字段,并指定字段的类型是文本,分词器分析器和搜索分词器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'
    }
]
for data in datas:
    es.index(index='news', doc_type='politics', body=data)

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

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

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 指定全文搜索。搜索栏为标题,内容为“中国领事馆”。搜索结果如下:

{
  "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。这是因为第一个匹配数据包含“中国”和“领事馆”这两个词。第二个匹配的数据不包含“Consulate”,而是包含“China”这个词,所以也检索到了,但是分数比较低。

因此,可以看出在搜索的过程中会搜索到对应字段的全文,并根据搜索关键字的相关性对结果进行排序。这是一个基本搜索引擎的原型。

此外,Elasticsearch 还支持很多查询方式。详情请参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl.html

以上就是Elasticsearch的基本介绍和Python操作Elasticsearch的基本用法,但这只是Elasticsearch的基本功能,还有更多强大的功能等着我们去探索。

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

知行编程网
知行编程网 关注:1    粉丝:1
这个人很懒,什么都没写
扫一扫二维码分享