
本工作簿使用一个由 Elastic 博客标题组成的简单 数据集 ,在 Elasticsearch 中实现 NLP 文本搜索。
你将索引博客文档,并使用 ingest pipeline 生成文本 embedding。随后,通过使用 NLP 模型,你可以使用自然语言对这些博客文档进行查询。
更多阅读:Elasticsearch:如何部署文本嵌入模型并将其用于语义搜索
前提条件
在开始之前,请创建一个 Elastic Cloud deployment,并启用 autoscale,确保至少有一个具有足够(4GB)内存的 机器学习 (ML)节点。同时确保 Elasticsearch 集群正在运行。
如果你还没有 Elastic deployment,可以注册免费的 Elastic Cloud 试用版。
安装软件包并导入模块
ini
`!python3 -m pip install sentence-transformers==2.7.0 eland elasticsearch transformers`AI写代码
开始之前,你需要安装所有必需的 Python 依赖项。
python
`
1. !python3 -m pip install sentence-transformers==2.7.0 "eland<9" "elasticsearch<9" transformers
3. # 导入模块
4. from elasticsearch import Elasticsearch
5. from getpass import getpass
6. from urllib.request import urlopen
7. import json
8. from time import sleep
`AI写代码
部署 NLP 模型
我们使用 [eland](https://www.elastic.co/guide/en/elasticsearch/client/eland/current/overview.html "eland") 工具安装一个 text_embedding 模型。这里使用 [all-MiniLM-L6-v2](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2 "all-MiniLM-L6-v2") 模型将搜索文本转换为 dense vector。
该模型会将你的搜索查询转换为向量,用于在存储于 Elasticsearch 中的文档集合上执行搜索。
安装文本 embedding NLP 模型
使用 [eland_import_hub_model](https://www.elastic.co/guide/en/elasticsearch/client/eland/current/machine-learning.html#ml-nlp-pytorch "eland_import_hub_model") 脚本下载并安装 all-MiniLM-L6-v2 Transformer 模型,并将 NLP 的 --task-type 设置为 text_embedding。
要获取 Cloud ID,请进入 Elastic Cloud,在 deployment 概览页面复制 Cloud ID。
为了验证请求身份,你可以使用 API key。或者,也可以使用 Cloud deployment 的用户名和密码。
ini
`
1. # https://www.elastic.co/search-labs/tutorials/install-elasticsearch/elastic-cloud#finding-your-cloud-id
2. ELASTIC_CLOUD_ID = getpass("Elastic Cloud ID: ")
4. # https://www.elastic.co/search-labs/tutorials/install-elasticsearch/elastic-cloud#creating-an-api-key
5. ELASTIC_API_KEY = getpass("Elastic Api Key: ")
`AI写代码
css
`
1. !eland_import_hub_model \
2. --cloud-id $ELASTIC_CLOUD_ID \
3. --hub-model-id sentence-transformers/all-MiniLM-L6-v2 \
4. --task-type text_embedding \
5. --es-api-key $ELASTIC_API_KEY \
6. --start \
7. --clear-previous
`AI写代码
连接到 Elasticsearch 集群
使用 deployment 的 Cloud ID 和 API Key 创建一个 Elasticsearch client 实例。在本示例中,我们使用上一步中的 API_KEY 和 CLOUD_ID。
你也可以使用 deployment 的用户名和密码进行身份验证。
ini
`
1. es = Elasticsearch(
2. cloud_id=ELASTIC_CLOUD_ID,
3. api_key=ELASTIC_API_KEY,
4. request_timeout=600
5. )
7. es.info() # 应返回集群信息
`AI写代码
创建 Ingest Pipeline
我们需要创建一个文本 embedding ingest pipeline,为 title 字段生成向量(文本)embedding。
下面的 pipeline 定义了一个 processor,用于调用 NLP 模型执行 inference。
ini
`
1. # ingest pipeline 定义
2. PIPELINE_ID = "vectorize_blogs"
4. es.ingest.put_pipeline(
5. id=PIPELINE_ID,
6. processors=[
7. {
8. "inference": {
9. "model_id": "sentence-transformers__all-minilm-l6-v2",
10. "target_field": "text_embedding",
11. "field_map": {"title": "text_field"},
12. }
13. }
14. ],
15. )
`AI写代码
创建带有 mapping 的索引
现在,在索引文档之前,我们先创建一个具有正确 mapping 的 Elasticsearch 索引。我们添加 text_embedding 字段,用于包含 model_id 和 predicted_value,以存储 embedding。
bash
`
1. # 定义索引名称
2. INDEX_NAME = "blogs"
4. # 标志,用于检查创建索引前是否删除已有索引
5. SHOULD_DELETE_INDEX = True
7. # 定义索引 mapping
8. INDEX_MAPPING = {
9. "properties": {
10. "title": {
11. "type": "text",
12. "fields": {
13. "keyword": {
14. "type": "keyword",
15. "ignore_above": 256
16. }
17. },
18. },
19. "text_embedding": {
20. "properties": {
21. "is_truncated": {
22. "type": "boolean"
23. },
24. "model_id": {
25. "type": "text",
26. "fields": {
27. "keyword": {
28. "type": "keyword",
29. "ignore_above": 256
30. }
31. },
32. },
33. "predicted_value": {
34. "type": "dense_vector",
35. "dims": 384,
36. "index": True,
37. "similarity": "l2_norm",
38. },
39. }
40. },
41. }
42. }
44. INDEX_SETTINGS = {
45. "index": {
46. "number_of_replicas": "1",
47. "number_of_shards": "1",
48. "default_pipeline": PIPELINE_ID,
49. }
50. }
52. # 检查是否需要在创建索引前删除已有索引
53. if SHOULD_DELETE_INDEX:
54. if es.indices.exists(index=INDEX_NAME):
55. print("Deleting existing %s" % INDEX_NAME)
56. es.indices.delete(index=INDEX_NAME, ignore=[400, 404])
58. print("Creating index %s" % INDEX_NAME)
60. es.indices.create(
61. index=INDEX_NAME,
62. mappings=INDEX_MAPPING,
63. settings=INDEX_SETTINGS,
64. ignore=[400, 404]
65. )
`AI写代码收起代码块
将数据索引到 Elasticsearch
现在,使用 ingest pipeline 索引示例博客数据。
注意:在开始索引之前,请确保你已经启动训练好的模型 deployment。
ini
`
1. url = "https://raw.githubusercontent.com/elastic/elasticsearch-labs/main/notebooks/integrations/hugging-face/blogs.json"
3. response = urlopen(url)
4. titles = json.loads(response.read())
6. actions = []
8. for title in titles:
9. actions.append({"index": {"_index": "blogs"}})
10. actions.append(title)
12. es.bulk(index="blogs", operations=actions)
14. sleep(5)
`AI写代码
查询数据集
下一步是执行查询,搜索相关博客。下面的示例使用我们上传到 Elasticsearch 的 sentence-transformers__all-minilm-l6-v2 模型,对 "model_text": "how to track network connections" 进行搜索。
整个过程只需一次查询,尽管内部实际上包含两个步骤。首先,查询会使用 NLP 模型为搜索文本生成一个向量;然后使用该向量在数据集中执行搜索。
最终,输出将显示按与搜索查询接近程度排序的文档列表。
ini
`
1. INDEX_NAME = "blogs"
3. source_fields = ["id", "title"]
5. query = {
6. "field": "text_embedding.predicted_value",
7. "k": 5,
8. "num_candidates": 50,
9. "query_vector_builder": {
10. "text_embedding": {
11. "model_id": "sentence-transformers__all-minilm-l6-v2",
12. "model_text": "how to track network connections",
13. }
14. },
15. }
17. response = es.search(
18. index=INDEX_NAME,
19. fields=source_fields,
20. knn=query,
21. source=False,
22. )
24. def show_results(results):
25. for result in results:
26. print(
27. f'{result["fields"]["title"]}\n'
28. f'Score: {result["_score"]}\n'
29. )
31. show_results(response.body["hits"]["hits"])
`AI写代码
输出:
less
`
1. ['Brewing in Beats: Track network connections']
2. Score: 0.5917864
4. ['Machine Learning for Nginx Logs - Identifying Operational Issues with Your Website']
5. Score: 0.40109876
7. ['Data Visualization For Machine Learning']
8. Score: 0.39027885
10. ['Logstash Lines: Introduce integration plugins']
11. Score: 0.36899462
13. ['Keeping up with Kibana: This week in Kibana for November 29th, 2019']
14. Score: 0.35690257
`AI写代码