如何写入 IMDB 电影数据并针对它运用 AI Builder 对它进行分享

24 阅读8分钟

在今天的文章中我们以一个 IMDB 电影数据为例来展示如何把数据写入到 Elasticsearch 中,并对它进行 AI 分析。

更多阅读:如何通过 Claude Code 来写入 CSV 数据到 Elasticsearch

准备工作

安装 Elasticsearch 及 Kibana

如果你还没有安装好自己的 Elasticsearch 及 Kibana,你可以启动云服务,比如阿里云,腾讯云,或者 Elastic Cloud。你可以参观看如下的视频:

建议你观看上面的 “为 AI 安装自己的 Elasticsearch 集群” 来进行安装。

为了能够使我们使用向量搜索对 overview 字段进行搜索,我们使用 E5 多语言模型。我们还需要进行如下的安装:

我们需要等后一点时间来等待下载完成。在安装过程中,如果由于任何原因导致安装不成功,你也可以直接使用如下的命令来删除它,然后再次下载:

`DELETE /_ml/trained_models/.multilingual-e5-small-elasticsearch?force=true`AI写代码

一旦下载完毕后,我们可以对它进行测试:

`GET _inference/_all`AI写代码

我们可以看到一个叫做 .multilingual-e5-small-elasticsearch 的 inference_id。我们可以做如下的一个简单的测试:

`

1.  POST _inference/.multilingual-e5-small-elasticsearch
2.  {
3.    "input": "The sky above the port was the color of television tuned to a dead channel."
4.  }

`AI写代码

很显然,这个推理端点工作正常。它可以帮我们把文字转换为向量。

下载 IMDB 数据

这个数据集可以在地址进行下载:

等下载完毕后,我们可以把它放到我们的目录中:

`

1.  $ pwd
2.  /Users/liuxg/python/imdb
3.  $ ls
4.  imdb_movies.csv.zip

`AI写代码

我们接下来把它进行解压缩:

`

1.  $ unzip imdb_movies.csv.zip 
2.  Archive:  imdb_movies.csv.zip
3.    inflating: imdb_movies.csv         
4.  $ ls
5.  imdb_movies.csv     imdb_movies.csv.zip

`AI写代码

我们可以看到上面的被解压缩的文件 imdb_movies.csv。文件的结构如下:

很显然,我们可以看到一个叫做 names, date_x, score, genre, overview 等字段。

写入数据到 Elasticsearch

我们有几种方法来写入数据。我们也可以仿照文章 “Elasticsearch:Retrievers 介绍 - Python Jupyter notebook” 来写入我们的数据。

使用 Kibana 上传写入

我们打开 Kibana:

经过调整后的 mapping 是这样的:

`

1.  {
2.    "properties": {
3.      "budget_x": {
4.        "type": "double"
5.      },
6.      "country": {
7.        "type": "keyword"
8.      },
9.      "crew": {
10.        "type": "text"
11.      },
12.      "date_x": {
13.        "type": "date",
14.        "format": "MM/dd/yyyy||MM/dd/yyyy[ ]"
15.      },
16.      "genre": {
17.        "type": "keyword"
18.      },
19.      "names": {
20.        "type": "text"
21.      },
22.      "orig_lang": {
23.        "type": "keyword"
24.      },
25.      "orig_title": {
26.        "type": "text"
27.      },
28.      "overview": {
29.        "type": "text",
30.        "copy_to": "overview_semantic"
31.      },
32.      "overview_semantic": {
33.        "type": "semantic_text",
34.        "inference_id": ".multilingual-e5-small-elasticsearch"
35.      },
36.      "revenue": {
37.        "type": "double"
38.      },
39.      "score": {
40.        "type": "double"
41.      },
42.      "status": {
43.        "type": "keyword"
44.      }
45.    }
46.  }

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

完美。我们已经成功地写入了所有的数据。我们可以直接点击 Agent Builder 对数据进行查询。

当然,在进行之前,我们也可以进入到 Kibana 查看数据:

`GET imdb/_mapping`AI写代码

查看我们的 mapping:

`

1.  {
2.    "imdb": {
3.      "mappings": {
4.        "_meta": {
5.          "created_by": "file-data-visualizer"
6.        },
7.        "properties": {
8.          "budget_x": {
9.            "type": "double"
10.          },
11.          "country": {
12.            "type": "keyword"
13.          },
14.          "crew": {
15.            "type": "text"
16.          },
17.          "date_x": {
18.            "type": "keyword"
19.          },
20.          "genre": {
21.            "type": "keyword"
22.          },
23.          "names": {
24.            "type": "text"
25.          },
26.          "orig_lang": {
27.            "type": "keyword"
28.          },
29.          "orig_title": {
30.            "type": "text"
31.          },
32.          "overview": {
33.            "type": "text",
34.            "copy_to": [
35.              "overview_semantic"
36.            ]
37.          },
38.          "overview_semantic": {
39.            "type": "semantic_text",
40.            "inference_id": ".multilingual-e5-small-elasticsearch",
41.            "model_settings": {
42.              "service": "elasticsearch",
43.              "task_type": "text_embedding",
44.              "dimensions": 384,
45.              "similarity": "cosine",
46.              "element_type": "float"
47.            }
48.          },
49.          "revenue": {
50.            "type": "double"
51.          },
52.          "score": {
53.            "type": "double"
54.          },
55.          "status": {
56.            "type": "keyword"
57.          }
58.        }
59.      }
60.    }
61.  }

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)收起代码块![](https://csdnimg.cn/release/blogv2/dist/pc/img/arrowup-line-top-White.png)

也可以针对数据进行查询:

这样我们的数据就已经写入完成了。

使用 Python 代码写入数据

针对有些开发者不是很喜欢使用 Upload file 上面的方法,你可以使用 Python 代码来实现上面的写入。针对我们的数据,我们可以有如下的代码来实现。在运行下面的代码之前,我们先运行下面的命令来删除已经写入的数据:

`DELETE imdb`AI写代码

我们先在当前目录创建一个叫做 .env 的文件:

`

1.  $ pwd
2.  /Users/liuxg/python/imdb
3.  $ ls -al
4.  total 19328
5.  drwxr-xr-x   6 liuxg  staff      192 Jul  9 11:38 .
6.  drwxr-xr-x@ 62 liuxg  staff     1984 Jul  9 09:48 ..
7.  -rw-r--r--   1 liuxg  staff      105 Jul  9 11:34 .env
8.  -rw-r--r--@  1 liuxg  staff  6723214 Apr 28  2023 imdb_movies.csv
9.  -rw-r--r--@  1 liuxg  staff  2980385 Jul  9 09:51 imdb_movies.csv.zip
10.  -rw-r--r--   1 liuxg  staff     4356 Jul  9 11:38 ingest_imdb.py

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)
`

1.  ES_URL="https://localhost:9200"
2.  ES_API_KEY="ckFQc1JKOEJHN2xFUjlaTlNKbUw6alU5MDgxOUlmM0hjLTE0WXdyQVNJUQ=="

`AI写代码

你需要根据自己的配置修改上面的 ES_URL 地址来指向自己的 Elasticsearch 端点。如果大家还不是很清楚如何得到 ES_API_KEY 的话,建议大家观看我之前的视频 “ Elastic 黑客松比赛说明”。我简单展示如下:

拷贝上面的 API key 即可:ckFQc1JKOEJHN2xFUjlaTlNKbUw6alU5MDgxOUlmM0hjLTE0WXdyQVNJUQ==

这样,我们的 .env 配置就完成了。

ingest_imdb.py

`

1.  #!/usr/bin/env python3
2.  """Ingest imdb_movies.csv into Elasticsearch, using connection settings from .env."""

4.  import csv
5.  import os
6.  import sys
7.  import urllib3

9.  from dotenv import load_dotenv
10.  from elasticsearch import Elasticsearch
11.  from elasticsearch.helpers import bulk, BulkIndexError
12.  from elastic_transport import TlsError

14.  INDEX_NAME = "imdb"
15.  CSV_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "imdb_movies.csv")
16.  BULK_CHUNK_SIZE = 50
17.  REQUEST_TIMEOUT = 300

19.  INDEX_MAPPING = {
20.      "mappings": {
21.          "properties": {
22.              "budget_x": {"type": "double"},
23.              "country": {"type": "keyword"},
24.              "crew": {"type": "text"},
25.              "date_x": {"type": "keyword"},
26.              "genre": {"type": "keyword"},
27.              "names": {"type": "text"},
28.              "orig_lang": {"type": "keyword"},
29.              "orig_title": {"type": "text"},
30.              "overview": {"type": "text", "copy_to": ["overview_semantic"]},
31.              "overview_semantic": {
32.                  "type": "semantic_text",
33.                  "inference_id": ".multilingual-e5-small-elasticsearch",
34.                  "model_settings": {
35.                      "service": "elasticsearch",
36.                      "task_type": "text_embedding",
37.                      "dimensions": 384,
38.                      "similarity": "cosine",
39.                      "element_type": "float",
40.                  },
41.              },
42.              "revenue": {"type": "double"},
43.              "score": {"type": "double"},
44.              "status": {"type": "keyword"},
45.          },
46.      }
47.  }

50.  def build_client(es_url: str, es_api_key: str) -> Elasticsearch:
51.      """Connect to Elasticsearch, working for both trusted and self-signed TLS certs."""
52.      try:
53.          client = Elasticsearch(
54.              es_url, api_key=es_api_key, verify_certs=True, request_timeout=REQUEST_TIMEOUT
55.          )
56.          client.info()
57.          return client
58.      except TlsError:
59.          print("Certificate could not be verified (self-signed?), retrying with verify_certs=False", file=sys.stderr)
60.          urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
61.          client = Elasticsearch(
62.              es_url, api_key=es_api_key, verify_certs=False, request_timeout=REQUEST_TIMEOUT
63.          )
64.          client.info()
65.          return client

68.  def ensure_index(client: Elasticsearch) -> None:
69.      if client.indices.exists(index=INDEX_NAME):
70.          print(f"Index '{INDEX_NAME}' already exists, skipping creation")
71.          return
72.      client.indices.create(index=INDEX_NAME, body=INDEX_MAPPING)
73.      client.cluster.health(index=INDEX_NAME, wait_for_status="yellow", timeout="30s")
74.      print(f"Created index '{INDEX_NAME}'")

77.  def to_float(value):
78.      value = (value or "").strip()
79.      if not value:
80.          return None
81.      try:
82.          return float(value)
83.      except ValueError:
84.          return None

87.  def read_docs(csv_path: str):
88.      with open(csv_path, newline="", encoding="utf-8") as f:
89.          reader = csv.DictReader(f)
90.          for row in reader:
91.              doc = {
92.                  "names": (row.get("names") or "").strip(),
93.                  "date_x": (row.get("date_x") or "").strip(),
94.                  "score": to_float(row.get("score")),
95.                  "genre": [g.strip() for g in (row.get("genre") or "").split(",") if g.strip()],
96.                  "overview": (row.get("overview") or "").strip(),
97.                  "crew": (row.get("crew") or "").strip(),
98.                  "orig_title": (row.get("orig_title") or "").strip(),
99.                  "status": (row.get("status") or "").strip(),
100.                  "orig_lang": (row.get("orig_lang") or "").strip(),
101.                  "budget_x": to_float(row.get("budget_x")),
102.                  "revenue": to_float(row.get("revenue")),
103.                  "country": (row.get("country") or "").strip(),
104.              }
105.              yield {"_index": INDEX_NAME, "_source": doc}

108.  def main() -> None:
109.      load_dotenv()
110.      es_url = os.environ["ES_URL"]
111.      es_api_key = os.environ["ES_API_KEY"]

113.      client = build_client(es_url, es_api_key)
114.      ensure_index(client)

116.      try:
117.          success, errors = bulk(
118.              client,
119.              read_docs(CSV_PATH),
120.              chunk_size=BULK_CHUNK_SIZE,
121.              raise_on_error=False,
122.          )
123.      except BulkIndexError as e:
124.          print(f"Bulk indexing failed: {e}", file=sys.stderr)
125.          sys.exit(1)

127.      print(f"Indexed {success} documents into '{INDEX_NAME}'")
128.      if errors:
129.          print(f"{len(errors)} documents failed to index", file=sys.stderr)
130.          for err in errors[:5]:
131.              print(err, file=sys.stderr)

134.  if __name__ == "__main__":
135.      main()

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)收起代码块![](https://csdnimg.cn/release/blogv2/dist/pc/img/arrowup-line-top-White.png)

运行上面的代码后,我们可以看到如下的结果:

`GET imdb/_mapping`AI写代码

使用 Agent Builder 对数据进行探索

我们首先使用默认的 Elastic AI Agent 来对数据进行探索:

我们选择自己的大模型。如果大家还不知道如何创建连接器,请观看我的视频: 为 AI 安装自己的 Elasticsearch 集群

我们可以看出来大模型可以为我们生成想要的统计结果。我们再来问一下:

`哪一年的生产的电影最多?`AI写代码

我们可以看到所使用的 ES|QL 查询。

`电影的类别有哪些?那个类别的电影最多?`AI写代码

是不是使用默认的 Elastic AI Agent 就可以做很多的事了?

你如果想定制自己的 Agents,那么你可以参考我之前的系列文章:

  • Elastic AI agent builder 介绍()()()()(

最后祝大家学习愉快!