Elasticsearch:Search tutorial 您所在的位置:网站首页 搜索的内容是啥 Elasticsearch:Search tutorial

Elasticsearch:Search tutorial

2024-07-15 11:52| 来源: 网络整理| 查看: 265

本实践教程将教你如何使用 Elasticsearch 构建完整的搜索解决方案。 在本教程中你将学习:

如何对数据集执行全文关键字搜索(可选使用过滤器)如何使用机器学习模型生成、存储和搜索密集向量嵌入如何使用 ELSER 模型生成和搜索稀疏向量如何使用 Elastic 的倒数排名融合 (RRF) 算法组合上述方法的搜索结果

本教程最重要的方面是,它将向你展示如何在你将在自己的计算机上运行的项目上实现所有这些功能,所有这些功能都通过小的增量步骤完成。

你将学习的示例是用 Python 编写的,但概念是通用的,可以应用于你最喜欢的语言或技术堆栈。

为了充分利用本教程,我们建议你遵循并运行所有示例。在如下的展示中,我将使用最新的 Elastic Stack 8.11 来进行展示。

安装

安装 Elasticsearch 及 Kibana

如果你还没有安装好自己的 Elasticsearch 及 Kibana,那么请参考一下的文章来进行安装:

如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch

Kibana:如何在 Linux,MacOS 及 Windows 上安装 Elastic 栈中的 Kibana

在安装的时候,请选择 Elastic Stack 8.x 进行安装。在安装的时候,我们可以看到如下的安装信息:

Python

你可以安装自己喜欢的 Python 版本。版本在 3.8 及以上。本教程假设你之前没有 Elasticsearch 或一般搜索主题的知识,但它希望你对以下技术有基本的熟悉,至少在初学者水平:

Python开发Python 的 Flask Web 框架操作系统中的命令提示符或终端应用程序

项目设置

在本教程中,你将使用一个基于 Flask Web 框架的小型 Python 应用程序。 以下部分提供了帮助你在计算机上设置和运行此应用程序的说明。 要完成本部分,你需要在操作系统的终端或命令提示符窗口上工作。

下载入门应用程序

单击下面的链接下载入门搜索应用程序。

下载教程入门应用程序

为你的项目找到合适的父目录,例如 Documents 目录,然后在其中提取 zip 文件的内容。 这应该添加一个搜索教程目录,其中包含多个子目录和文件。

安装 Python 依赖包

从你的终端,切换到上一节中创建的 search-tutorial 目录。遵循 Python 最佳实践,你现在将创建一个虚拟环境,一个专用于该项目的私有 Python 环境。 使用以下命令执行此操作:

python3 -m venv .venv $ pwd /Users/liuxg/python/search-tutorial $ python3 -m venv .venv $ ls -al total 144 drwx------ 11 liuxg staff 352 Jan 4 09:38 . drwxr-xr-x 115 liuxg staff 3680 Jan 2 20:09 .. -rw-r--r-- 1 liuxg staff 34 Oct 31 19:34 .flaskenv drwxr-xr-x 6 liuxg staff 192 Jan 4 09:38 .venv -rw-r--r--@ 1 liuxg staff 1085 Nov 1 15:23 LICENSE -rw-r--r-- 1 liuxg staff 110 Nov 7 20:21 README.md -rw-r--r-- 1 liuxg staff 409 Nov 7 19:46 app.py -rw-r--r-- 1 liuxg staff 51647 Oct 31 15:54 data.json -rw-r--r--@ 1 liuxg staff 745 Oct 31 19:05 requirements.txt drwx------ 3 liuxg staff 96 Jan 2 20:09 static drwx------ 5 liuxg staff 160 Jan 2 20:09 templates

此命令在 .venv (dot-venv) 目录中创建 Python 虚拟环境。 你可以将此命令中的 .venv 替换为你喜欢的任何名称。 请注意,在某些 Python 安装中,你可能需要使用 python 而不是 python3 来调用 Python 解释器。

下一步是激活虚拟环境,这是使该虚拟环境成为你所在终端会话的活动 Python 环境的一种方法。如果你使用的是基于 UNIX 的操作系统(例如 Linux 或 macOS),请激活 虚拟环境如下:

source .venv/bin/activate $ source .venv/bin/activate (.venv) $ pwd /Users/liuxg/python/search-tutorial

如果你在 Microsoft Windows 计算机上的 WSL 环境中工作,上述激活命令也适用。 但如果你使用的是 Windows 命令提示符或 PowerShell,激活命令会有所不同:

.venv\Scripts\activate

激活虚拟环境后,命令行提示符将更改为显示环境名称:

(.venv) $ _

注意:如果你以前没有使用过虚拟环境,则应记住激活命令不是永久性的,仅适用于输入命令的终端会话。 如果你打开第二个终端窗口,或者在前一天关闭计算机后返回继续学习本教程,则必须重复激活命令。

配置 Python 环境的最后一步是安装入门应用程序所需的一些包。 确保上一步中已激活虚拟环境,然后运行以下命令安装这些依赖项:

pip install -r requirements.txt

拷贝 Elasticsearch 证书

我们把 Elasticsearch 的证书拷贝到当前的目录下:

(.venv) $ pwd /Users/liuxg/python/search-tutorial (.venv) $ cp ~/elastic/elasticsearch-8.11.0/config/certs/http_ca.crt . (.venv) $ ls http_ca.crt http_ca.crt

运行应用

此时,你应该能够使用以下命令启动应用程序:

flask run

要确认应用程序正在运行,请打开浏览器并导航到 http://localhost:5001。

注意:早期阶段的应用程序只是一个空壳。 如果你愿意,你可以在搜索框中输入内容并请求搜索,但响应始终是没有结果。 在以下部分中,你将了解如何在 Elasticsearch 索引中加载一些内容并执行搜索。

Flask 应用程序配置为在开发模式下运行。 当它检测到源文件已更改时,它将自动重新启动以合并更改。 当你继续学习本教程时,你可以让该终端会话保持应用程序运行,并且当你进行更改时,应用程序将重新启动以进行更新。

全文搜索

在本教程的这一部分中,你将学习如何使用 Elasticsearch 的全文搜索功能。 这将向你介绍几个核心主题,例如使用 Python 客户端库、创建和更新索引、进行查询以及使用搜索结果,所有这些也适用于你稍后将学习的更高级的搜索方法。

设置 Elasticsearch Python 客户端

在本部分中,你将安装适用于 Python 的 Elasticsearch 客户端库并使用它连接到 Elasticsearch 服务。

安装

Elasticsearch 客户端库是一个与 pip 一起安装的 Python 包。 确保之前创建的虚拟环境已激活,然后运行以下命令安装客户端:

pip install elasticsearch $ pip3 install elasticsearch Looking in indexes: http://mirrors.aliyun.com/pypi/simple/ Requirement already satisfied: elasticsearch in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (8.11.1) Requirement already satisfied: elastic-transport=8 in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from elasticsearch) (8.10.0) Requirement already satisfied: urllib3=1.26.2 in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from elastic-transport=8->elasticsearch) (2.1.0) Requirement already satisfied: certifi in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from elastic-transport=8->elasticsearch) (2023.11.17) $ pip3 list | grep elasticsearch elasticsearch 8.11.1 rag-elasticsearch 0.0.1 /Users/liuxg/python/rag-elasticsearch/my-app/packages/rag-elasticsearch

始终建议使用所有依赖项更新 requirements.txt 文件,因此这是更新此文件以包含新安装的软件包的好时机。 从终端运行以下命令:

pip3 freeze > requirements.txt

我们可以看到最终的 requirements.txt 文件中的 elasticsearch 版本被修正了:

连接到 Elasticsearch

要创建与 Elasticsearch 服务的连接,必须使用适当的连接选项创建 Elasticsearch 对象。

在代码编辑器中创建一个新的 search.py 文件,该文件位于 search-tutorial 目录中。 search.py 文件将定义所有搜索函数。 为搜索功能创建一个单独的文件的想法是,这将使你可以轻松地提取该文件并稍后将其添加到你自己的项目中。

在 search.py中输入以下代码添加 Search 类:

import json from pprint import pprint import os import time from dotenv import load_dotenv from elasticsearch import Elasticsearch load_dotenv() class Search: def __init__(self): self.es = Elasticsearch() # >> 提示符,你可以在其中输入 Python 语句。

导入 Search 类如下:

from search import Search

接下来,实例化新类:

es = Search()

你应该看到一条已连接的消息,后面是客户端的 info() 方法返回的信息。 除了标识符和版本号的差异之外,输出应如下所示:

(.venv) $ pwd /Users/liuxg/python/search-tutorial (.venv) $ python Python 3.11.6 (v3.11.6:8b6ee5ba3b, Oct 2 2023, 11:18:21) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> from search import Search >>> es = Search() Connected to Elasticsearch! {'cluster_name': 'elasticsearch', 'cluster_uuid': 'SXGzrN4dSXW1t0pkWXGfjg', 'name': 'liuxgm.local', 'tagline': 'You Know, for Search', 'version': {'build_date': '2023-11-04T10:04:57.184859352Z', 'build_flavor': 'default', 'build_hash': 'd9ec3fa628c7b0ba3d25692e277ba26814820b20', 'build_snapshot': False, 'build_type': 'tar', 'lucene_version': '9.8.0', 'minimum_index_compatibility_version': '7.0.0', 'minimum_wire_compatibility_version': '7.17.0', 'number': '8.11.0'}}

如果收到错误,请确保在 .env 文件中输入正确的凭据。更多关于如何连接到 Elasticsearch 的知识,请参阅文章 “Elasticsearch:关于在 Python 中使用 Elasticsearch 你需要知道的一切 - 8.x”。

将 Elasticsearch 与 Flask 应用程序集成

本节的最后一步是将迄今为止完成的工作集成到你之前安装的小 Flask 应用程序中。 目标是应用程序在启动时自动创建与 Elasticsearch 的连接。

为此,请在代码编辑器中打开 app.py。 在现有导入下方添加 search.py 模块的导入语句:

from search import Search

然后找到创建 app 变量的行,然后创建新 Search 类的实例:

es = Search()

就是这样! 现在应用程序有一个 es 对象可以在需要时使用。 如果你仍在终端中运行 Flask 应用程序,则保存文件后你应该会看到应用程序重新加载。 重新加载的结果是,由 Search 类构造函数打印的连接信息应该出现,并且从现在起每次应用程序重新启动时都会继续出现。

如果你没有运行 Flask 应用程序,现在是启动它的好时机。 更改到终端窗口中的项目目录,激活 Python 虚拟环境,然后使用以下命令启动应用程序:

flask run

为了帮助你在收到错误时进行故障排除,以下是带有集成 Elasticsearch 客户端的 app.py 的完整代码:

app.py

import re from flask import Flask, render_template, request from search import Search app = Flask(__name__) es = Search() @app.get('/') def index(): return render_template('index.html') @app.post('/') def handle_search(): query = request.form.get('query', '') return render_template( 'index.html', query=query, results=[], from_=0, total=0) @app.get('/document/') def get_document(id): return 'Document not found'

当我们修改完这个文件后,我们可以在运行 flask 的 terminal 中看到如下的输出:

创建一个 Elasticsearch 索引

Elasticsearch 中两个非常重要的概念是文档和索引。你如果对这个还是很糊涂的话,那么请详细阅读我之前的文章 “Elasticsearch 中的一些重要概念: cluster, node, index, document, shards 及 replica”。

文档是字段及其关联值的集合。 要使用 Elasticsearch,你必须将数据组织到文档中,然后将所有文档添加到索引中。 你可以将索引视为以高度优化的格式存储的文档集合,旨在执行高效的搜索。

如果你使用过其他数据库,你可能知道许多数据库需要模式定义,它本质上是对你要存储的所有字段及其类型的描述。 如果需要,Elasticsearch 索引可以配置模式,但它也可以自动从数据本身派生模式(Elasticsearch 根据数据的类型进行推测)。 在本节中,你将让 Elasticsearch 自行计算模式,这对于文本、数字和日期等简单数据类型非常有效。 稍后,在了解更复杂的数据类型后,你将学习如何提供显式模式定义。

创建索引

这是使用 Python 客户端库创建 Elasticsearch 索引的方法:

self.es.indices.create(index='my_documents')

在此示例中,self.es 是 Elasticsearch 类的实例,在本教程中它存储在 search.py 的 Search 类中。 Elasticsearch 部署可用于存储多个索引,每个索引都由名称标识,例如上例中的 my_documents。

也可以删除索引:

self.es.indices.delete(index='my_documents')

如果你尝试使用已分配给现有索引的名称创建索引,则会收到错误消息。 有时,创建一个索引并自动删除该索引的先前实例(如果存在)会很有用。 这在开发应用程序时特别有用,因为你可能需要多次重新生成索引。

让我们在 search.py 中添加一个 create_index() 辅助方法。 在代码编辑器中打开此文件,然后在底部添加以下代码,保留现有内容不变:

class Search: # ... def create_index(self): self.es.indices.delete(index='my_documents', ignore_unavailable=True) self.es.indices.create(index='my_documents')

create_index() 方法首先删除名为 my_documents 的索引。 ignore_unavailable=True 选项可防止在找不到索引名称时此调用失败。 该方法中的以下行创建一个具有相同名称的全新索引。

提示:本教程中的示例应用程序需要一个 Elasticsearch 索引,因此它将索引名称硬编码为 my_documents。 对于使用多个索引的更复杂的应用程序,你可以考虑接受索引名称作为参数。

将文档添加到索引

在 Python 的 Elasticsearch 客户端库中,文档表示为键/值字段的字典。 具有字符串值的字段会自动建立索引以进行全文和关键字搜索,但除了字符串之外,你还可以使用其他字段类型,例如数字、日期和布尔值,这些字段类型也会建立索引以进行过滤等高效操作。 你还可以构建复杂的数据结构,其中字段设置为列表或带有子项的字典。了解有关 Elasticsearch 类型的更多信息。

要将文档插入索引,请使用 Elasticsearch 客户端的 index() 方法。 例如:

document = { 'title': 'Work From Home Policy', 'contents': 'The purpose of this full-time work-from-home policy is...', 'created_on': '2023-11-02', } response = es.index(index='my_documents', body=document) print(response['_id'])

index() 方法的返回值是 Elasticsearch 服务返回的响应。 此响应中返回的最重要的信息是一个键名为 _id 的项目,表示在将文档插入索引时分配给该文档的唯一标识符。 该标识符可用于检索、删除或更新文档。

现在你已经知道如何插入文档了,让我们继续在 search.py 中构建一个有用的 helpers 库,并为 Search 类添加一个新的 insert_document() 方法。 在 search.py 底部添加此方法:

class Search: # ... def insert_document(self, document): return self.es.index(index='my_documents', body=document)

该方法接受 Elasticsearch 客户端和来自调用者的文档,并将文档插入到 my_documents 索引中,返回服务的响应。

注意:本教程不涉及这些操作(修改及删除),但 Elasticsearch 客户端也可以修改和删除文档。 请参阅 Python 库文档中的 Elasticsearch 类参考,了解所有可用的操作。更多内容,请阅读文章  “Elasticsearch:关于在 Python 中使用 Elasticsearch 你需要知道的一切 - 8.x”。

从 JSON 文件提取文档

设置新的 Elasticsearch 索引时,你可能需要导入大量文档。 对于本教程,入门项目包括一个 data.json 文件,其中包含一些 JSON 格式的数据。 在本节中,你将学习如何将该文件中包含的所有文档导入到索引中。

data.json 中包含的文档结构如下:

name:文档标题url:外部站点上托管的文档的 URLsummary:文档内容的简短摘要content:文档正文created_on:创建日期updated_at:更新日期(如果文档从未更新过,则可能会没有这个项)category:文档的类别,可以是 github、sharepoint 或 teamsrolePermissions:角色权限列表

此时,建议你在编辑器中打开 data.json 以熟悉要使用的数据。

本质上,导入大量文档与在 for 循环中导入一个文档没有什么不同。 要导入 data.json 文件的全部内容,你可以执行以下操作:

import json from search import Search es = Search() with open('data.json', 'rt') as f: documents = json.loads(f.read()) for document in documents: es.insert_document(document)

虽然这种方法有效,但扩展性不佳。 如果你必须插入大量文档,则需要对 Elasticsearch 服务进行尽可能多的调用。 遗憾的是,每个 API 调用都会产生性能成本,而且该服务还设有速率限制,无法快速进行大量调用。 由于这些原因,最好使用 Elasticsearch 服务的批量插入功能,该功能允许在单个 API 调用中将多个操作传递给服务。

下面显示的 insert_documents() 方法(你应该将其添加到 search.py 的底部)使用 bulk() 方法在一次调用中插入所有文档:

def insert_documents(self, documents): operations = [] for document in documents: operations.append({'index': {'_index': 'my_documents'}}) operations.append(document) return self.es.bulk(operations=operations)

该方法接受文档列表。 它不是单独添加每个文档,而是组装一个称为操作的列表,然后将该列表传递给 bulk() 方法。 对于每个文档,两个条目会添加到操作列表中:

对要执行的操作的描述,设置为索引,并以索引名称作为参数给出。文档的实际数据

处理批量请求时,Elasticsearch 服务从头开始遍历操作列表并执行请求的操作。

在文档中了解有关 bulk() 方法的更多信息

我们在当前的目录下运行如下的脚步来写入文档:

ingest.py

重新生成索引

当你学习本教程时,你将需要重新生成索引几次。 要简化此操作,请向 search.py 添加 reindex() 方法:

class Search: # ... def reindex(self): self.create_index() with open('data.json', 'rt') as f: documents = json.loads(f.read()) return self.insert_documents(documents)

此方法结合了之前创建的 create_index() 和 insert_documents() 方法,因此只需一次调用即可销毁旧索引(如果存在)并构建并重新填充新索引。

注意:对大量文档建立索引时,最好将文档列表分成较小的集合,并分别导入每个集合。

为了使这个方法更容易调用,让我们通过 flask 命令公开它。 在代码编辑器中打开 app.py 并在底部添加以下函数:

@app.cli.command() def reindex(): """Regenerate the Elasticsearch index.""" response = es.reindex() print(f'Index with {len(response["items"])} documents created ' f'in {response["took"]} milliseconds.')

@app.cli.command()  decorator 告诉 Flask 框架将此函数注册为自定义命令,该命令将作为 Flask reindex 提供。 命令的名称取自函数的名称,并且文档字符串包含在此处,因为 Flask 在 --help 文档中使用它。

reindex() 函数的响应,也就是 Elasticsearch 客户端的 bulk() 方法的响应,包含一些有用的项目,可用于构造良好的状态消息。 特别是,response['took'] 是调用的持续时间(以毫秒为单位),response['items'] 是每个操作的各个结果的列表,实际上并没有直接用处,但列表的长度提供了插入文档的计数。

通过从终端会话运行 Flask --help 来查看效果,确保 Python 虚拟环境已激活(如果您的终端会话仍在运行 Flask 应用程序,则可以打开第二个终端窗口)。 在帮助屏幕的末尾,您应该会看到作为可用命令包含的 reindex 选项以及 Flask 框架提供的其他选项:

flash --help (.venv) $ pwd /Users/liuxg/python/search-tutorial (.venv) $ flask --help Connected to Elasticsearch! {'cluster_name': 'elasticsearch', 'cluster_uuid': 'SXGzrN4dSXW1t0pkWXGfjg', 'name': 'liuxgm.local', 'tagline': 'You Know, for Search', 'version': {'build_date': '2023-11-04T10:04:57.184859352Z', 'build_flavor': 'default', 'build_hash': 'd9ec3fa628c7b0ba3d25692e277ba26814820b20', 'build_snapshot': False, 'build_type': 'tar', 'lucene_version': '9.8.0', 'minimum_index_compatibility_version': '7.0.0', 'minimum_wire_compatibility_version': '7.17.0', 'number': '8.11.0'}} Usage: flask [OPTIONS] COMMAND [ARGS]... A general utility script for Flask applications. An application to load must be given with the '--app' option, 'FLASK_APP' environment variable, or with a 'wsgi.py' or 'app.py' file in the current directory. Options: -e, --env-file FILE Load environment variables from this file. python- dotenv must be installed. -A, --app IMPORT The Flask application or factory function to load, in the form 'module:name'. Module can be a dotted import or file path. Name is not required if it is 'app', 'application', 'create_app', or 'make_app', and can be 'name(args)' to pass arguments. --debug / --no-debug Set debug mode. --version Show the Flask version. --help Show this message and exit. Commands: reindex Regenerate the Elasticsearch index. routes Show the routes for the app. run Run a development server. shell Run a shell in the app context.

现在,当你想要生成一个干净的索引时,你所需要做的就是运行 flask reindex。

搜素基础

现在你已经构建了 Elasticsearch 索引并向其中加载了一些文档,你已经准备好实现全文搜索了。

搜索将如何进行

让我们快速回顾一下搜索解决方案在教程应用程序中的工作原理。 Flask 应用程序运行后,你可以访问 http://localhost:5001 访问主页面,如下所示:

呈现此页面的代码在 app.py 文件中实现:

@app.get('/') def index(): return render_template('index.html')

这是一个非常简单的端点,用于呈现 HTML 模板。 在 Flask 应用程序中,模板位于 templates 子目录中,因此你会在其中找到应用程序中包含的此模板和其他模板。

让我们看看文件 templates/index.html 中搜索字段的实现。 这是该模板的相关部分:



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有