Elasticsearch是一个基于文档的NoSQL数据库,它允许开发者无需SQL知识即可使用。不仅如此,Elasticsearch 还是一个现代的搜索和分析引擎,基于Apache Lucene构建,具有分布式特性,已被众多处理海量数据的公司广泛采用。Elasticsearch的搜索能力是其与其他NoSQL数据库如MongoDB或CouchDB的主要区别。由于Elasticsearch的分布式特性,它可以轻松处理大数据,无需任何麻烦。Elasticsearch通常与其他技术如Kibana和Logstash一起使用,构成了ELK技术栈。
在本文中,将学习如何在Docker容器中运行Elasticsearch,并使用Python编程语言执行基本的CRUD操作和不同类型的搜索操作。要在本地运行Elasticsearch,可以从安装它,或者在Docker容器中运行它。请注意,如果不使用Docker,需要在本地机器上安装Java才能运行Elasticsearch。将详细解释后者。
首先,在Windows机器上安装Docker。可以从下载Docker Desktop。安装过程相当简单直接。现在Docker安装成功,让尝试在Docker容器中运行一个Elasticsearch实例。
要在容器中运行Elasticsearch,可以手动从下载Elasticsearch镜像,然后使用它启动一个容器。但缺点是,在大多数情况下可能会失败,因为Docker需要至少分配4GB的内存。这可以在设置中的高级标签中访问和配置。这可能需要正确配置机器上的WSL2,对于大多数新手来说可能是一个挑战。
坐等片刻,因为Elasticsearch镜像相当大,这将需要一些时间。一旦Elasticsearch实例启动并运行,可以转到容器标签页,点击运行Elasticsearch实例的容器,它将为提供通过互联网访问Elasticsearch的URL。
复制并粘贴URL到新的浏览器窗口,响应将如下所示。现在Elasticsearch实例正在运行,让开始编程部分。
将使用“elasticsearch”模块,这是一个免费且可用的模块,可以使用pip像安装其他Python模块一样安装。要安装Python的Elasticsearch驱动程序,请运行以下命令。
$ pip install elasticsearch
现在已经安装了ElasticsearchPython模块,让尝试连接到在Docker容器中运行的Elasticsearch实例。
from elasticsearch import Elasticsearch
es = Elasticsearch(['http://localhost:49154']) # 连接到elasticsearch
es.ping()
True
可以看到代码返回true,表示已经成功连接到Elasticsearch实例。现在已经连接到ES实例,让看看如何执行基本的CRUD操作和一些简单的搜索操作,这是Elasticsearch提供近实时(NRT)搜索结果的主要亮点。
首先,让了解Elasticsearch中的“Index”概念。顾名思义,许多人可能会认为这与其他数据库如MySQL、MongoDB等中的索引概念相同。简单答案是不。Elasticsearch中的Index代表存储所有数据的数据库。所以,不要将其与索引概念混淆。现在已经对ES中的索引有了基本了解,让尝试向数据库中插入一些文档。
要插入文档,可以直接使用“index()”函数,它接受索引名称和文档数据作为参数。循环遍历列表中的每个文档并调用index函数插入大量数据将耗时。ES有“bulk()”函数用于这种情况,将其大量数据写入数据库。可以参阅他们的文档了解更多详情。就本文而言,将只使用“index()”函数,以保持事情尽可能简单。
employees_data = [
{
{ "name": "Vishnu"}
'age': 21,
{ "programming_languages": ["C++", "python", "nodejs"]}
},
{
{ "name": "Sanjay"}
'age': 23,
{ "programming_languages": ["python", "C#"]}
},
{
{ "name": "Arjun"}
'age': 33,
{ "programming_languages": ["C++", "Ruby"]}
},
{
{ "name": "Ram"}
'age': 27,
{ "programming_languages": ["Rust", "python"]}
}
]
for data in employees_data: es.index(index='employees', document=data)
现在已经插入了一些文档,让尝试获取它们。Elasticsearch公开了API,如果不舒服编程,也可以使用它们。让看一个使用API获取数据库中所有文档的示例。在浏览器的新标签页中输入以下URL。
如果ES实例运行在不同的端口,这个URL可能对不起作用。所以,请确保使用正确的端口号来访问ES数据库。
URL: http://localhost:49153/employees/_search
现在让尝试使用Python获取具有其ID的单个文档。为此,可以使用“get()”函数,它接受两个参数:索引和文档ID。可以从上面的图像中提取所有文档的ID。
res = es.get(index="employees", id='snO1AYIBqhIpBwyVnPS_') # 获取文档
print(res['_source'])
{'name': 'Vishnu', 'age': 21, 'programming_languages': ['C++', 'python', 'nodejs']}
现在已经看到了如何从数据库中获取文档,让了解如何更新文档。使用“update()”函数来更新文档,它接受索引、文档ID和更新后的数据作为参数。让现在就看看这个操作。
es.update(index="employees", id='snO1AYIBqhIpBwyVnPS_', doc={'country': 'India'}) # 更新文档
res = es.get(index="employees", id='snO1AYIBqhIpBwyVnPS_') # 获取文档
print(res['_source'])
{'name': 'Vishnu', 'age': 21, 'programming_languages': ['C++', 'python', 'nodejs'], 'country': 'India'}
可以看到文档已经更新,因为它有一个新的键值对,即国家参数。现在,让看看如何在数据库中删除文档。为此,可以使用“delete()”函数,它接受索引和文档ID作为参数。
res = es.delete(index="employees", id='snO1AYIBqhIpBwyVnPS_')
print(res)
ObjectApiResponse({'_index': 'employees', '_id': 'snO1AYIBqhIpBwyVnPS_', '_version': 3, 'result': 'deleted', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 5, '_primary_term': 1})
现在已经执行了所有基本的CRUD操作,让看看Elasticsearch中的一些搜索操作。假设想搜索名为“Ram”的文档。现在,希望这是一个精确搜索,而不是类似模糊搜索。对于这两种情况,都使用“search()”函数,只是使用“match”关键字进行精确的全字符串匹配,而使用“fuzzy”关键字进行简单的模糊搜索。让首先看看全字符串匹配。
es.search(index="employees", query={"match": {'name':'Ram'}}) # 精确字符串搜索
ObjectApiResponse({'took': 10, 'timed_out': False, '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0}, 'hits': {'total': {'value': 1, 'relation': 'eq'}, 'max_score': 1.3862942, 'hits': [{'_index': 'employees', '_id': 'tXO1AYIBqhIpBwyVnfQ3', '_score': 1.3862942, '_source': {'name': 'Ram', 'age': 27, 'programming_languages': ['Rust', 'python']}}]}})
现在,让看看如何执行简单的模糊搜索。为此,将尝试获取所有在programming_languages键中包含python的文档。
es.search(index="employees", query={"fuzzy": {'programming_languages':'python'}}) # 模糊搜索
ObjectApiResponse({'took': 11, 'timed_out': False, '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0}, 'hits': {'total': {'value': 2, 'relation': 'eq'}, 'max_score': 0.308732, 'hits': [{'_index': 'employees', '_id': 's3O1AYIBqhIpBwyVnfQe', '_score': 0.308732, '_source': {'name': 'Sanjay', 'age': 23, 'programming_languages': ['python', 'C#']}}, {'_index': 'employees', '_id': 'tXO1AYIBqhIpBwyVnfQ3', '_score': 0.308732, '_source': {'name': 'Ram', 'age': 27, 'programming_languages': ['Rust', 'python']}}]}})
现在让看看如何使用正则表达式进行搜索。同样,可以使用“search()”函数,但需要添加regexp关键字。让现在就看看这个操作。让尝试获取所有包含字母“n”的名称。
es.search(index="employees", query={"regexp": {'name':'.*n.*'}}) # 正则表达式搜索
ObjectApiResponse({'took': 47, 'timed_out': False, '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0}, 'hits': {'total': {'value': 2, 'relation': 'eq'}, 'max_score': 1.0, 'hits': [{'_index': 'employees', '_id': 's3O1AYIBqhIpBwyVnfQe', '_score': 1.0, '_source': {'name': 'Sanjay', 'age': 23, 'programming_languages': ['python', 'C#']}}, {'_index': 'employees', '_id': 'tHO1AYIBqhIpBwyVnfQt', '_score': 1.0, '_source': {'name': 'Arjun', 'age': 33, 'programming_languages': ['C++', 'Ruby']}}]}})