在今天的文章中,我們將很快地通過(guò) Docker 來(lái)快速地設(shè)置 Elasticsearch 及 Kibana,并設(shè)置 Elasticsearch 為向量搜索。
拉取 Docker 鏡像
docker pull docker.elastic.co/elasticsearch/elasticsearch:8.12.2
docker pull docker.elastic.co/kibana/kibana:8.12.2
啟動(dòng) Elasticsearch 及 Kibana 容器
docker network create elastic
docker run -d --name elasticsearch --net elastic -p 9200:9200 -p 9300:9300 -m 1GB -e "discovery.type=single-node" -e "ELASTIC_PASSWORD=password" docker.elastic.co/elasticsearch/elasticsearch:8.12.2
docker run -d --name kibana --net elastic -p 5601:5601 docker.elastic.co/kibana/kibana:8.12.2
$ docker run -d --name elasticsearch --net elastic -p 9200:9200 -p 9300:9300 -m 1GB -e "discovery.type=single-node" -e "ELASTIC_PASSWORD=password" docker.elastic.co/elasticsearch/elasticsearch:8.12.2
39dc9085f239edb3c963de4fb122f0ec02f78a6311abd8297cf046c025cd2618
$ docker run -d --name kibana --net elastic -p 5601:5601 docker.elastic.co/kibana/kibana:8.12.2
2766a300b3fd165f793f5f47b55748b2e9d4b016ea78b5c23565442e2c4cdfb5
在上面,我們指定了 elasic 超級(jí)用戶(hù)的密碼為 password。這在下面將要使用到。
驗(yàn)證容器是否已啟動(dòng)并正在運(yùn)行:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2766a300b3fd docker.elastic.co/kibana/kibana:8.12.2 "/bin/tini -- /usr/l…" About a minute ago Up About a minute 0.0.0.0:5601->5601/tcp kibana
39dc9085f239 docker.elastic.co/elasticsearch/elasticsearch:8.12.2 "/bin/tini -- /usr/l…" 3 minutes ago Up 3 minutes 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp elasticsearch
從上面我們可以看到 Elasticsarch 及 Kibana 已經(jīng)完全運(yùn)行起來(lái)了。我們可以在瀏覽器中進(jìn)行驗(yàn)證:
docker exec -it elasticsearch /bin/bash
docker logs -f kibana
$ docker logs -f kibana
Kibana is currently running with legacy OpenSSL providers enabled! For details and instructions on how to disable see https://www.elastic.co/guide/en/kibana/8.12/production.html#openssl-legacy-provider
{"log.level":"info","@timestamp":"2024-03-22T01:28:37.598Z","log.logger":"elastic-apm-node","ecs.version":"8.10.0","agentVersion":"4.2.0","env":{"pid":7,"proctitle":"/usr/share/kibana/bin/../node/bin/node","os":"linux 6.4.16-linuxkit","arch":"arm64","host":"2766a300b3fd","timezone":"UTC+00","runtime":"Node.js v18.18.2"},"config":{"active":{"source":"start","value":true},"breakdownMetrics":{"source":"start","value":false},"captureBody":{"source":"start","value":"off","commonName":"capture_body"},"captureHeaders":{"source":"start","value":false},"centralConfig":{"source":"start","value":false},"contextPropagationOnly":{"source":"start","value":true},"environment":{"source":"start","value":"production"},"globalLabels":{"source":"start","value":[["git_rev","f5bd489c5ff9c676c4f861c42da6ea99ae350832"]],"sourceValue":{"git_rev":"f5bd489c5ff9c676c4f861c42da6ea99ae350832"}},"logLevel":{"source":"default","value":"info","commonName":"log_level"},"metricsInterval":{"source":"start","value":120,"sourceValue":"120s"},"serverUrl":{"source":"start","value":"https://kibana-cloud-apm.apm.us-east-1.aws.found.io/","commonName":"server_url"},"transactionSampleRate":{"source":"start","value":0.1,"commonName":"transaction_sample_rate"},"captureSpanStackTraces":{"source":"start","sourceValue":false},"secretToken":{"source":"start","value":"[REDACTED]","commonName":"secret_token"},"serviceName":{"source":"start","value":"kibana","commonName":"service_name"},"serviceVersion":{"source":"start","value":"8.12.2","commonName":"service_version"}},"activationMethod":"require","message":"Elastic APM Node.js Agent v4.2.0"}
[2024-03-22T01:28:38.276+00:00][INFO ][root] Kibana is starting
[2024-03-22T01:28:38.320+00:00][INFO ][node] Kibana process configured with roles: [background_tasks, ui]
[2024-03-22T01:28:42.183+00:00][INFO ][plugins-service] Plugin "cloudChat" is disabled.
[2024-03-22T01:28:42.192+00:00][INFO ][plugins-service] Plugin "cloudExperiments" is disabled.
[2024-03-22T01:28:42.193+00:00][INFO ][plugins-service] Plugin "cloudFullStory" is disabled.
[2024-03-22T01:28:42.501+00:00][INFO ][plugins-service] Plugin "profilingDataAccess" is disabled.
[2024-03-22T01:28:42.501+00:00][INFO ][plugins-service] Plugin "profiling" is disabled.
[2024-03-22T01:28:42.587+00:00][INFO ][plugins-service] Plugin "securitySolutionServerless" is disabled.
[2024-03-22T01:28:42.587+00:00][INFO ][plugins-service] Plugin "serverless" is disabled.
[2024-03-22T01:28:42.587+00:00][INFO ][plugins-service] Plugin "serverlessObservability" is disabled.
[2024-03-22T01:28:42.587+00:00][INFO ][plugins-service] Plugin "serverlessSearch" is disabled.
[2024-03-22T01:28:42.929+00:00][INFO ][http.server.Preboot] http server running at http://0.0.0.0:5601
[2024-03-22T01:28:42.996+00:00][INFO ][plugins-system.preboot] Setting up [1] plugins: [interactiveSetup]
[2024-03-22T01:28:43.004+00:00][INFO ][preboot] "interactiveSetup" plugin is holding setup: Validating Elasticsearch connection configuration…
[2024-03-22T01:28:43.019+00:00][INFO ][root] Holding setup until preboot stage is completed.
i Kibana has not been configured.
Go to http://0.0.0.0:5601/?code=897018 to get started.
Your verification code is: 897 018
我們把上面的 enrollment token 及 verification code 填入下面的方框里:
注意:由于一些原因,在上面顯示的地址不是 localhost,而是電腦上的另外一個(gè)地址,比如 172.18.0.2:9200。這個(gè)并不影響我們的配置。
這樣我們就成功地登錄了。
創(chuàng)建索引
現(xiàn)在,讓我們創(chuàng)建 “movies” 索引。 我們將使用 text-embedding-3-small 模型來(lái)生成 title 字段的向量嵌入并將其存儲(chǔ)為 title_embedding。 該模型生成長(zhǎng)度為 1536 的嵌入。因此我們需要將 title_embedding 字段映射指定為具有 1536 維的密集向量。
PUT /movies
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"genre": {
"type": "keyword"
},
"release_year": {
"type": "integer"
},
"title_embedding": {
"type": "dense_vector",
"dims": 1536
}
}
}
}
讓我們使用 Elasticsearch Python 客戶(hù)端插入一些文檔。
Python 客戶(hù)端需要 `ssl_assert_fingerprint` 才能連接到 Elasticsearch。 讓我們使用以下命令來(lái)獲取它:
openssl s_client -connect localhost:9200 -servername localhost -showcerts </dev/null 2>/dev/null | openssl x509 -fingerprint -sha256 -noout -in /dev/stdin
$ openssl s_client -connect localhost:9200 -servername localhost -showcerts </dev/null 2>/dev/null | openssl x509 -fingerprint -sha256 -noout -in /dev/stdin
sha256 Fingerprint=20:67:39:6C:33:C0:D6:AC:E2:E3:A5:2E:56:6C:57:4F:91:DC:41:4D:99:9B:7F:0F:1C:20:AD:E2:20:FE:1E:1B
寫(xiě)入文檔到 Elasticsearch
現(xiàn)在我們可以在電影索引中插入一些文檔。
我們現(xiàn)在 terminal 中打入如下的命令:
export OPENAI_API_KEY="YourOpenAiKey"
在上面,請(qǐng)?zhí)钊胱约荷暾?qǐng)的 OpenAI key。
請(qǐng)按照下面的命令來(lái)安裝所需要的包:
pip3 install elasticsearch python-dotenv
我們創(chuàng)建如下的 python 應(yīng)用:
write_index.py
from elasticsearch import Elasticsearch
from openai import OpenAI
import os
OPENAI_API_KEY= os.getenv("OPENAI_API_KEY")
es = Elasticsearch(
"https://localhost:9200",
ssl_assert_fingerprint='20:67:39:6C:33:C0:D6:AC:E2:E3:A5:2E:56:6C:57:4F:91:DC:41:4D:99:9B:7F:0F:1C:20:AD:E2:20:FE:1E:1B',
basic_auth=("elastic", "password")
)
openai = OpenAI(api_key=OPENAI_API_KEY)
movies = [
{"title": "Inception", "genre": "Sci-Fi", "release_year": 2010},
{"title": "The Shawshank Redemption", "genre": "Drama", "release_year": 1994},
{"title": "The Godfather", "genre": "Crime", "release_year": 1972},
{"title": "Pulp Fiction", "genre": "Crime", "release_year": 1994},
{"title": "Forrest Gump", "genre": "Drama", "release_year": 1994}
]
# Indexing movies
for movie in movies:
movie['title_embedding'] = openai.embeddings.create(
input=[movie['title']], model='text-embedding-3-small'
).data[0].embedding
es.index(index="movies", document=movie)
我們使用如下的命令來(lái)運(yùn)行腳本:
python3 write_index.py
我們可以在 Kibana 中進(jìn)行查看:
GET movies/_search
搜索索引
比方說(shuō),我們想要搜索與片名《godfather》緊密匹配的電影。 我們可以使用K最近鄰(KNN)算法來(lái)搜索相關(guān)文檔。 我們會(huì)將搜索限制為僅顯示 1 個(gè)最接近的匹配結(jié)果。
首先我們需要獲得單詞 Godfather 的向量表示:
vector_value = openai_client.embeddings.create(
input=["Godfather"], model='text-embedding-3-small'
).data[0].embedding
現(xiàn)在我們可以搜索電影索引來(lái)獲取與片名《Godfather》緊密匹配的電影。 在我們的例子中,它應(yīng)該與標(biāo)題為《Godfather》的電影文檔匹配。
query_string = {
"field": "title_embedding",
"query_vector": vector_value,
"k": 1,
"num_candidates": 100
}
results = es_client.search(index="movies", knn=query_string, source_includes=["title", "genre", "release_year"])
print(results['hits']['hits'])
完整的 Python 應(yīng)用如下:
search_index.py
from elasticsearch import Elasticsearch
from openai import OpenAI
import os
OPENAI_API_KEY= os.getenv("OPENAI_API_KEY")
es = Elasticsearch(
"https://localhost:9200",
ssl_assert_fingerprint='20:67:39:6C:33:C0:D6:AC:E2:E3:A5:2E:56:6C:57:4F:91:DC:41:4D:99:9B:7F:0F:1C:20:AD:E2:20:FE:1E:1B',
basic_auth=("elastic", "password")
)
openai = OpenAI(api_key=OPENAI_API_KEY)
vector_value = openai.embeddings.create(
input=["Godfather"], model='text-embedding-3-small'
).data[0].embedding
query_string = {
"field": "title_embedding",
"query_vector": vector_value,
"k": 1,
"num_candidates": 100
}
results = es.search(index="movies", knn=query_string, source_includes=["title", "genre", "release_year"])
print(results['hits']['hits'])
運(yùn)行上面的代碼:
$ python3 search_index.py
[{'_index': 'movies', '_id': 'koeTZI4BvK48CYytTCuI', '_score': 0.8956262, '_source': {'title': 'The Godfather', 'genre': 'Crime', 'release_year': 1972}}]
很顯然,它找到了 Godfather 這個(gè)文檔。
很多開(kāi)發(fā)者可能想問(wèn),我們是不是也可以使用中文來(lái)進(jìn)行搜索呢?
我們嘗試如下的代碼:
search_index.py
from elasticsearch import Elasticsearch
from openai import OpenAI
import os
OPENAI_API_KEY= os.getenv("OPENAI_API_KEY")
es = Elasticsearch(
"https://localhost:9200",
ssl_assert_fingerprint='20:67:39:6C:33:C0:D6:AC:E2:E3:A5:2E:56:6C:57:4F:91:DC:41:4D:99:9B:7F:0F:1C:20:AD:E2:20:FE:1E:1B',
basic_auth=("elastic", "password")
)
openai = OpenAI(api_key=OPENAI_API_KEY)
vector_value = openai.embeddings.create(
input=["教父"], model='text-embedding-3-small'
).data[0].embedding
query_string = {
"field": "title_embedding",
"query_vector": vector_value,
"k": 1,
"num_candidates": 100
}
results = es.search(index="movies", knn=query_string, source_includes=["title", "genre", "release_year"])
print(results['hits']['hits'])
在上面的代碼中,我們使用 “教父” 而不是 Godfather。運(yùn)行上面的代碼,它顯示:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-854800.html
$ python3 search_index.py
[{'_index': 'movies', '_id': 'koeTZI4BvK48CYytTCuI', '_score': 0.6547822, '_source': {'title': 'The Godfather', 'genre': 'Crime', 'release_year': 1972}}]
很顯然,它也同樣找到 Godfather 這個(gè)電影。它說(shuō)明這個(gè)大語(yǔ)言模型支持多語(yǔ)言的搜索。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-854800.html
到了這里,關(guān)于如何使用 Elasticsearch 作為向量數(shù)據(jù)庫(kù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!