在本文中,我们使用预训练的 BERT 模型和 Elasticsearch 来构建搜索引擎。 Elasticsearch 最近发布了带有向量场的文本相似性(text similarity search with vector field)搜索。 另一方面,你可以使用 BERT 将文本转换为固定长度的向量。 因此,一旦我们将文档通过 BERT 转换为向量并存储到 Elasticsearch 中,我们就可以使用 Elasticsearch 和 BERT 搜索相似的文档。

这篇文章通过以下架构实现了一个带有 Elasticsearch 和 BERT 的搜索引擎。 在这里,我们使用 Docker 将整个系统分为三个部分:应用程序、BERT 和 Elasticsearch。 目的是使扩展每个服务更容易。

整个系统是在 docker-compose.yamlin 中编写的,位于以下 GitHub 存储库中。 请查看存储库:GitHub - liu-xiao-guo/bertsearch: Elasticsearch with BERT for advanced document search.

$ pwd
/Users/liuxg/python/bertsearch
$ tree -L 3
.
├── LICENSE
├── README.md
├── bertserving
│   ├── Dockerfile
│   └── entrypoint.sh
├── docker-compose.yaml
├── docs
│   ├── architecture.png
│   ├── diagram.key
│   └── example.png
├── example
│   ├── __init__.py
│   ├── create_documents.py
│   ├── create_index.py
│   ├── example.csv
│   ├── index.json
│   ├── index_documents.py
│   └── requirements.txt
└── web├── Dockerfile├── app.py├── requirements.txt└── templates└── index.html

请注意:在本文的展示中,我使用 TensorFlow 来进行展示。更对关于 Pytorch 的展示,请参阅我之前的文章 “Elastic:开发者上手指南” 中的 “NLP - 自然语言处理” 部分。另外,由于 TensorFlow 里的指令限制,该展示不支持 Apple chipset 的电脑。你需要在 Intel 运行的机器上运行。

这篇文章的计划是:

  • 下载预训练的 BERT 模型
  • 设置环境变量
  • 启动 Docker 容器
  • 创建 Elasticsearch 索引
  • 创建文件
  • 索引文件

安装

你需要安装好自己的 Docker 环境。你需要安装自己的 Python。需要在版本 3.0 及以上。另外,为了能够让项目里的 Python 能够正常运行,你需要按照如下的命令来安装如下的库:

pip install bert_serving_server
pip install bert_serving_client

你需要确保这里安装的库和 docker-compose.yml 里的所定义的库的版本是一致的。

web/requirements.txt

bert-serving-client==1.10.0
elasticsearch==8.6.1
Flask==2.2.2

bertserving/Dockerfile

FROM tensorflow/tensorflow:1.12.0-py3
RUN pip install -U pip
RUN pip install --no-cache-dir bert-serving-server==1.10.0
COPY ./ /app
COPY ./entrypoint.sh /app
WORKDIR /app
ENTRYPOINT ["/app/entrypoint.sh"]
CMD []

example/requirements.txt

bert-serving-client==1.10.0
elasticsearch==7.0.4
pandas==0.25.1

如上所示,我们选择的 bert-serving-client 及 bert-serving-server 的版本都是 1.10.0。

在本展示中,我将使用最新的 Elastic Stack 8.6.1 来进行展示,但是在 Elasticsearch 的配置中,我不使用安全配置。

docker-compose.yml

version: '3.9'
services:web:build: ./webports:- "5100:5100"environment:- INDEX_NAMEdepends_on:- elasticsearch- bertservingnetworks:- elastic   elasticsearch:container_name: elasticsearchimage: elasticsearch:8.6.1environment:- discovery.type=single-node- ES_JAVA_OPTS=-Xms1g -Xmx1g- xpack.security.enabled=falsevolumes:- es_data:/usr/share/elasticsearch/dataports:- target: 9200published: 9200networks:- elastic   kibana:container_name: kibanaimage: kibana:8.6.1ports:- target: 5601published: 5601depends_on:- elasticsearchnetworks:- elastic   bertserving:container_name: bertservingbuild: ./bertservingports:- "5555:5555"- "5556:5556"environment:- PATH_MODEL=${PATH_MODEL}volumes:- "${PATH_MODEL}:/model"networks:- elastic
volumes:es_data:driver: localnetworks:elastic:name: elasticdriver: bridge

下载 pre-trained BERT 模型

首先,下载预训练的 BERT 模型。 以下命令是下载英文模型的示例:

wget https://storage.googleapis.com/bert_models/2018_10_18/cased_L-12_H-768_A-12.zip
unzip cased_L-12_H-768_A-12.zip
$ pwd
/Users/liuxg/python/bertsearch
$ wget https://storage.googleapis.com/bert_models/2018_10_18/cased_L-12_H-768_A-12.zip
--2023-02-27 09:40:16--  https://storage.googleapis.com/bert_models/2018_10_18/cased_L-12_H-768_A-12.zip
Resolving storage.googleapis.com (storage.googleapis.com)... 142.251.36.16
Connecting to storage.googleapis.com (storage.googleapis.com)|142.251.36.16|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 404261442 (386M) [application/zip]
Saving to: ‘cased_L-12_H-768_A-12.zip’cased_L-12_H-768_A- 100%[===================>] 385.53M  16.0MB/s    in 24s     2023-02-27 09:40:41 (16.0 MB/s) - ‘cased_L-12_H-768_A-12.zip’ saved [404261442/404261442]$ unzip cased_L-12_H-768_A-12.zip
Archive:  cased_L-12_H-768_A-12.zipcreating: cased_L-12_H-768_A-12/inflating: cased_L-12_H-768_A-12/bert_model.ckpt.meta  inflating: cased_L-12_H-768_A-12/bert_model.ckpt.data-00000-of-00001  inflating: cased_L-12_H-768_A-12/vocab.txt  inflating: cased_L-12_H-768_A-12/bert_model.ckpt.index  inflating: cased_L-12_H-768_A-12/bert_config.json
$ ls
LICENSE                   cased_L-12_H-768_A-12     docs
README.md                 cased_L-12_H-768_A-12.zip example
bertserving               docker-compose.yaml       web

从上面,我们可以看出来在当前的目录里创建了一个叫做 cased_L-12_H-768_A-12 的子目录。它将在下面的 bertserving 容器中被使用到。

设置环境变量

你需要将预训练的 BERT 模型和 Elasticsearch 的索引名称设置为环境变量。 这些变量在 Docker 容器中使用。 下面是一个将 jobsearch 指定为索引名称并将 ./cased_L-12_H-768_A-12 指定为模型路径的示例:

export PATH_MODEL=./cased_L-12_H-768_A-12
export INDEX_NAME=jobsearch

启动 docker

现在,让我们使用 Docker compose 启动 Docker 容器。 这里要启动三个容器:应用程序容器、BERT 容器和 Elasticsearch 容器。我们按照如下的命令来启动所有的容器:

docker-compose up

一旦成功启动完毕后,我们可以用在 http://localhost:9200 来访问 Elasticsearch,并在地址 http://localhost:5601 访问 Kibana。

$ curl http://localhost:9200
{"name" : "d996f0e69e91","cluster_name" : "docker-cluster","cluster_uuid" : "KiXF66HWSw2RSEXTiHKP2Q","version" : {"number" : "8.6.1","build_flavor" : "default","build_type" : "docker","build_hash" : "180c9830da956993e59e2cd70eb32b5e383ea42c","build_date" : "2023-01-24T21:35:11.506992272Z","build_snapshot" : false,"lucene_version" : "9.4.2","minimum_wire_compatibility_version" : "7.17.0","minimum_index_compatibility_version" : "7.0.0"},"tagline" : "You Know, for Search"
}

我们可以通过如下的命令来查看所有的真正运行的容器:

docker ps
$ docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED          STATUS          PORTS                                                  NAMES
a043a2b1cabc   bertsearch_web           "python app.py"          3 minutes ago    Up 3 minutes    0.0.0.0:5100->5100/tcp                                 bertsearch_web_1
2c1e20206eff   bertsearch_bertserving   "/app/entrypoint.sh"     3 minutes ago    Up 3 minutes    6006/tcp, 0.0.0.0:5555-5556->5555-5556/tcp, 8888/tcp   bertserving
7eb3a9422c50   kibana:8.6.1             "/bin/tini -- /usr/l…"   16 minutes ago   Up 16 minutes   0.0.0.0:5601->5601/tcp                                 kibana
d996f0e69e91   elasticsearch:8.6.1      "/bin/tini -- /usr/l…"   16 minutes ago   Up 16 minutes   0.0.0.0:9200->9200/tcp, 9300/tcp                       elasticsearch

从上面,我们可以看出来有四个正在运行的容器。请注意,我建议你为 Docker 分配更多内存(超过 8GB)。 因为 BERT 容器需要大内存。

我们的 bertserving 服务运行于 http://localhost:5555,而 web 服务运行于 http://localhost:5100。我们可以在 docker-compose.yml 里进行查看。

创建 Elasticsearch 索引

你可以使用创建索引 API 将新索引添加到 Elasticsearch 集群。 创建索引时,你可以指定以下内容:

  • 索引的设置
  • 索引中字段的映射
  • 索引别名

例如,如果要创建包含 title、text 和 text_vector 字段的 jobsearch 索引,可以通过以下命令创建索引:

python example/create_index.py --index_file=example/index.json --index_name=jobsearch

上面书命令在 Elasticsearch 中创建了具有如下配置的一个叫做 jobsearch 的索引:

{"settings": {"number_of_shards": 2,"number_of_replicas": 1},"mappings": {"dynamic": "true","_source": {"enabled": "true"},"properties": {"title": {"type": "text"},"text": {"type": "text"},"text_vector": {"type": "dense_vector","dims": 768}}}
}

我们可以通过如下的命令来查看:

GET jobsearch

注意:text_vector 的 dims 值必须与预训练的 BERT 模型的 dims 相匹配。

创建文档

创建索引后,你就可以为一些文档编制索引了。 这里的重点是使用 BERT 将你的文档转换为向量。 结果向量存储在 text_vector 字段中。 让我们将你的数据转换为 JSON 文档。在本示例中,我们是用了一个简单的 example.csv 文件:

example/example.csv

"Title","Description"
"Saleswoman","a woman whose job is to sell a product or service in a given territory, in a store, or by telephone"
"Software Developer","Hire Expert Software Engineers and Developers With Crowdbotics"
"Chief Financial Officer","a senior executive responsible for managing the financial actions of a company. "
"General Manager","esponsible for improving efficiency and increasing departmental profits while managing the company’s overall operations."
"Network Administrator","installing, monitoring, troubleshooting, and upgrading network infrastructure, including both hardware and software components"

如上所示,我们的 csv 文件中,含有两个字段:Title 及 Description。我们将把 Description 这个部分矢量化,以方便我们下面的搜索。

python example/create_documents.py --data=example/example.csv --index_name=jobsearch

完成脚本后,你可以得到如下的 JSON 文档:

$ pwd
/Users/liuxg/python/bertsearch
$ ls
LICENSE                   cased_L-12_H-768_A-12     docs
README.md                 cased_L-12_H-768_A-12.zip example
bertserving               docker-compose.yaml       web
$ python example/create_documents.py --data=example/example.csv --index_name=jobsearch
$ ls
LICENSE                   cased_L-12_H-768_A-12.zip example
README.md                 docker-compose.yaml       web
bertserving               docs
cased_L-12_H-768_A-12     documents.jsonl

从上面的输出中,我们可以看出来,运行命令后,当前目录下多了一个文件  documents.jsonl。它的文件格式如下:

上述格式显然是易于我们使用 bulk 命令来进行批写入的格式。

写入文档到 Elasticsearch

将数据转换为 JSON 后,你可以将 JSON 文档添加到指定索引并使其可搜索。

python example/index_documents.py

执行完上面的命令后,我们可以在 Kibana 中进行查看:

GET jobsearch/_search

打开浏览器

转到 http://localhost:5100。 下面是一些搜索的例子。

从上面的搜索结果中,我们可以看出来,尽管我们输入的词并不完全匹配文字中的描述,但是它还是给了我们最想要的最为相关的结果。这些结果是按照相关性进行排列显示的。

上面的搜索,其实在 web 里是使用了如下的搜索命令:

GET jobsearch/_search
{"_source": ["text", "title"], "query": {"script_score": {"script": {"source": "cosineSimilarity(params.query_vector, 'text_vector')","params": {"query_vector": [0.480839341878891,-0.3990676701068878,-0.1494527906179428,-0.6091867685317993,-0.014144758693873882,-0.053846489638090134,0.727445125579834,-0.009675377979874611,-0.29119399189949036,0.14104360342025757,0.2982104420661926,0.5848511457443237,...]}} }
}

特别值得指出的是:在最新的 Elasticsearch 发布版中,我们可以使用 knn 搜索。具体例子可以参考文章 “Elasticsearch:运用 Python 实现在 Elasticsearch 上的向量搜索”。你可以尝试修改 web 里的搜索部分来完成这个练习。这里就不再展示了。

Elasticsearch:使用 Elasticsearch 和 BERT 构建搜索引擎 - TensorFlow相关推荐

  1. 使用Node.js和Elasticsearch构建搜索引擎

    这篇文章是由同行审查马克·布朗 , Vildan Softic和莫里茨克罗格 . 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态! Elasticsearch是一个开放源 ...

  2. elasticsearch+element UI el-autocomplete+springboot实现搜索引擎

    elasticsearch+element UI el-autocomplete+springboot实现搜索引擎 vue前端代码: <template><el-autocomple ...

  3. 【Nutch2.2.1基础教程之2.1】集成Nutch/Hbase/Solr构建搜索引擎之一:安装及运行【单机环境】...

    1.下载相关软件,并解压 版本号如下: (1)apache-nutch-2.2.1 (2) hbase-0.90.4 (3)solr-4.9.0 并解压至/usr/search 2.Nutch的配置 ...

  4. 【Nutch2.3基础教程】集成Nutch/Hadoop/Hbase/Solr构建搜索引擎:安装及运行【集群环境】

    1.下载相关软件,并解压 版本号如下: (1)apache-nutch-2.3 (2) hadoop-1.2.1 (3)hbase-0.92.1 (4)solr-4.9.0 并解压至/opt/jedi ...

  5. 【Nutch2.2.1基础教程之2.1】集成Nutch/Hbase/Solr构建搜索引擎之一:安装及运行【单机环境】

    1.下载相关软件,并解压 版本号如下: (1)apache-nutch-2.2.1 (2) hbase-0.90.4 (3)solr-4.9.0 并解压至/usr/search 2.Nutch的配置 ...

  6. 【Elasticsearch】Elasticsearch 存储桶聚合

    1.概述 翻译:https://iridakos.com/programming/2018/10/22/elasticsearch-bucket-aggregations [Elasticsearch ...

  7. 【Elasticsearch】Elasticsearch自定义评分的N种方法

    1.概述 首先参考文章:[Elasticsearch]Elasticsearch 相关度评分 TF&IDF 然后转载文章:实战 | Elasticsearch自定义评分的N种方法 2.三个问题 ...

  8. 【Elasticsearch】Elasticsearch analyzer 中文 分词器

    1.概述 转载: https://blog.csdn.net/tzs_1041218129/article/details/77887767 分词器首先看文章:[Elasticsearch]Elast ...

  9. SpringBoot2整合ElasticSearch(包含ElasticSearch入门+spring-boot-starter-data-elasticsearch)

    前言 作为互联网热点知识的ElasticSearch,怎能不学.如果你有空余时间,欢迎入门:如果你没空余时间,也欢迎走马观花看一眼.走过如果不要错过,这是一篇自我感觉相对对入门者来说比较全面的文章了, ...

最新文章

  1. Win7共享文件夹简单?这个共享问题可以难倒90%的人
  2. linux命令查询邮件发送状态,Linux发邮件之mail命令详解
  3. axure怎么做5秒倒计时_五个月宝宝早教,5个月婴儿早教怎么做
  4. 传闻称马斯克从创始人手中偷走了特斯拉公司,马斯克回击...
  5. U盘启动盘恢复为普通盘
  6. 浅谈UWB室内定位(二)
  7. Joint European Conference on Machine Learning and Knowledge Discovery in Databases(ECML-PKDD)会议怎么样?
  8. 菜鸟的Python学习之路(流水账)
  9. linux sigar 进程监控,Linux 下使用Sigar 获取CPU 使用率
  10. python去重txt文本_Python实现的txt文件去重功能示例
  11. 作为运营,如何在职场上野蛮生长
  12. BZOJ 2002 HNOI2010 弹飞绵羊 分块
  13. Libre密聊——致力于私密聊天的用心APP
  14. 【调剂】河北农业大学2020年硕士研究生招生调剂工作办法
  15. VC6.0修改工程名字方法
  16. Excel无法打开文件新建 XLSX 工作表.xlsx,因为文件格式或文件扩展名无效。请确定文件未损坏解决办法【笔记】
  17. dz php7.1语言包,discuz 插件语言包
  18. Windows10 中 Apple 云盘 iCloud Drive 默认在 C 盘下的存储目录迁移到其他盘符的指定目录
  19. 幼儿园观察记录的目的和目标_幼儿园观察记录:如何让幼儿在区角活动中真正动起来...
  20. 十月下旬腾讯 网易游戏 百度迅雷校园招聘笔试题集锦 第271 330题

热门文章

  1. 每日一练社区(C/C++)(困难)----擅长编码的小k
  2. 常见的运动控制器控制方案
  3. 清华电子工程系和计算机系,清华大学电子工程系王生进教授:脑电识别与脑机交互...
  4. 当数据库中存在某个表的年龄大于vacuum_freeze_table_age,就会执行急切冻结过程
  5. IDEA远程调试linux上的SpringBoot项目
  6. transferto方法的应用_NIO的transferTo方法
  7. coot怎么调用python_pymol使用笔记教程范本.doc
  8. 使用GEO数据库获取感兴趣实验的差异表达基因
  9. Ceres Power和潍柴动力敲定战略协作及合资协议
  10. 今天会用了正则表达式