Elasticsearch:运用向量搜索通过图像搜索找到你的小狗

作者:ALEX SALGADO

你是否曾经遇到过这样的情况:你在街上发现了一只丢失的小狗,但不知道它是否有主人? 了解如何使用向量搜索或图像搜索来做到这一点。

通过图像搜索找到你的小狗

您是否曾经遇到过这样的情况:你在街上发现了一只丢失的小狗,但不知道它是否有主人? 在 Elasticsearch 中通过图像处理使用向量搜索,此任务可以像漫画一样简单。

想象一下这个场景:在一个喧闹的下午,路易吉,一只活泼的小狗,在 Elastic 周围散步时不小心从皮带上滑落,发现自己独自在繁忙的街道上徘徊。 绝望的主人正在各个角落寻找他,用充满希望和焦虑的声音呼唤着他的名字。 与此同时,在城市的某个地方,一位细心的人注意到这只小狗表情茫然,决定提供帮助。 很快,他们给路易吉拍了一张照片,并利用所在公司的向量图像搜索技术,开始在数据库中进行搜索,希望能找到有关这只小逃亡者主人的线索。

如果你想在阅读时跟踪并执行代码,请访问在 Jupyter Notebook (Google Collab) 上运行的文件 Python 代码。

架构

我们将使用 Jupyter Notebook 来解决这个问题。 首先,我们下载要注册的小狗的图像,然后安装必要的软件包。

注意:要实现此示例,我们需要在使用图像数据填充向量数据库之前在 Elasticsearch 中创建索引。

  • 首先部署 Elasticsearch(我们为你提供 14 天的免费试用期)。
  • 在此过程中,请记住存储要在 Python 代码中使用的凭据(用户名、密码)。
  • 为简单起见,我们将使用在 Jupyter Notebook (Google Colab) 上运行的 Python 代码。

下载代码 zip 文件并安装必要的软件包

!git clone https://github.com/salgado/image-search-01.git
!pip -q install Pillow sentence_transformers elasticsearch

让我们创建 4 个类来帮助我们完成这项任务,它们是:

  • Util 类:负责处理前期任务和 Elasticsearch 索引维护。
  • Dog 类:负责存储我们小狗的属性。
  • DogRepository 类:负责数据持久化任务。
  • DogService 类:它将成为我们的服务层。

Util class

Util 类提供了用于管理 Elasticsearch 索引的实用方法,例如创建和删除索引。

方法

  • create_index():在 Elasticsearch 中创建一个新索引。
  • delete_index():从 Elasticsearch 中删除现有索引。
### Util class
from elasticsearch import Elasticsearch, exceptions as es_exceptions
import getpassclass Util:@staticmethoddef get_index_name():return "dog-image-index"@staticmethoddef get_connection():es_cloud_id = getpass.getpass('Enter Elastic Cloud ID:  ')es_user = getpass.getpass('Enter cluster username:  ')es_pass = getpass.getpass('Enter cluster password:  ')es = Elasticsearch(cloud_id=es_cloud_id,basic_auth=(es_user, es_pass))es.info() # should return cluster inforeturn es@staticmethoddef create_index(es: Elasticsearch, index_name: str):# Specify index configurationindex_config = {"settings": {"index.refresh_interval": "5s","number_of_shards": 1},"mappings": {"properties": {"image_embedding": {"type": "dense_vector","dims": 512,"index": True,"similarity": "cosine"},"dog_id": {"type": "keyword"},"breed": {"type" : "keyword"},"image_path" : {"type" : "keyword"},"owner_name" : {"type" : "keyword"},"exif" : {"properties" : {"location": {"type": "geo_point"},"date": {"type": "date"}}}}}}# Create indexif not es.indices.exists(index=index_name):index_creation = es.indices.create(index=index_name, ignore=400, body=index_config)print("index created: ", index_creation)else:print("Index  already exists.")@staticmethoddef delete_index(es: Elasticsearch, index_name: str):# delete indexes.indices.delete(index=index_name, ignore_unavailable=True)

如果你是自构建的集群,你可以参考文章 “Elasticsearch:关于在 Python 中使用 Elasticsearch 你需要知道的一切 - 8.x” 来了解如何使用客户端来连接 Elasticsearch 集群。

Dog class

Dog 类代表一只狗及其属性,例如 ID、图像路径、品种、所有者姓名和图像嵌入。

属性

  • dog_id:狗的 ID。
  • image_path:狗图像的路径。
  • breed:狗的品种。
  • owner_name:狗的主人的名字。
  • image_embedding:狗的图像嵌入。

方法:

  • __init__():初始化一个新的 Dog 对象。
  • generate_embedding():生成狗的图像嵌入。
  • to_dict():将 Dog 对象转换为字典。
import os
from sentence_transformers import SentenceTransformer
from PIL import Image# domain class
class Dog:model = SentenceTransformer('clip-ViT-B-32')def __init__(self, dog_id, image_path, breed, owner_name):self.dog_id = dog_idself.image_path = image_pathself.breed = breedself.image_embedding = Noneself.owner_name = owner_name@staticmethoddef get_embedding(image_path: str):temp_image = Image.open(image_path)return Dog.model.encode(temp_image)def generate_embedding(self):self.image_embedding = Dog.get_embedding(self.image_path)def __repr__(self):return (f"Image(dog_id={self.dog_id}, image_path={self.image_path}, "f"breed={self.breed}, image_embedding={self.image_embedding}, "f"owner_name={self.owner_name})")def to_dict(self):return {'dog_id': self.dog_id,'image_path': self.image_path,'breed': self.breed,'image_embedding': self.image_embedding,'owner_name': self.owner_name}

DogRepository class

DogRepository 类提供了从 Elasticsearch 保存和检索狗数据的方法。

方法

  • insert():将一条新狗插入 Elasticsearch。
  • bulk_insert():将多条狗批量插入到Elasticsearch中。
  • search_by_image():通过图像搜索相似的狗。
from typing import List, Dict
# persistence layer
class DogRepository:def __init__(self, es_client: Elasticsearch, index_name: str = "dog-image-index"):self.es_client = es_clientself._index_name = index_nameUtil.create_index(es_client, index_name)def insert(self, dog: Dog):dog.generate_embedding()document = dog.__dict__self.es_client.index(index=self._index_name, document=document)def bulk_insert(self, dogs: List[Dog]):operations = []for dog in dogs:operations.append({"index": {"_index": self._index_name}})operations.append(dog.__dict__)self.es_client.bulk(body=operations)def search_by_image(self, image_embedding: List[float]):field_key = "image_embedding"knn = {"field": field_key,"k": 2,"num_candidates": 100,"query_vector": image_embedding,"boost": 100}# The fields to retrieve from the matching documentsfields = ["dog_id", "breed", "owner_name","image_path", "image_embedding"]try:resp = self.es_client.search(index=self._index_name,body={"knn": knn,"_source": fields},size=1)# Return the search resultsreturn respexcept Exception as e:print(f"An error occurred: {e}")return {}

DogService Class

DogService 类提供管理狗数据的业务逻辑,例如插入和搜索狗。

方法

  • insert_dog():将一条新狗插入 Elasticsearch。
  • search_dogs_by_image():通过图像搜索相似的狗。

from typing import List, Dict
# persistence layer
class DogRepository:def __init__(self, es_client: Elasticsearch, index_name: str = "dog-image-index"):self.es_client = es_clientself._index_name = index_nameUtil.create_index(es_client, index_name)def insert(self, dog: Dog):dog.generate_embedding()document = dog.__dict__self.es_client.index(index=self._index_name, document=document)def bulk_insert(self, dogs: List[Dog]):operations = []for dog in dogs:operations.append({"index": {"_index": self._index_name}})operations.append(dog.__dict__)self.es_client.bulk(body=operations)def search_by_image(self, image_embedding: List[float]):field_key = "image_embedding"knn = {"field": field_key,"k": 2,"num_candidates": 100,"query_vector": image_embedding,"boost": 100}# The fields to retrieve from the matching documentsfields = ["dog_id", "breed", "owner_name","image_path", "image_embedding"]try:resp = self.es_client.search(index=self._index_name,body={"knn": knn,"_source": fields},size=1)# Return the search resultsreturn respexcept Exception as e:print(f"An error occurred: {e}")return {}

上面介绍的类(classes)为构建狗数据管理系统奠定了坚实的基础。 Util 类提供了用于管理 Elasticsearch 索引的实用方法。 Dog 类代表狗的属性。 DogRepository 类提供了从 Elasticsearch 保存和检索狗数据的方法。 DogService 类提供了高效的狗数据管理的业务逻辑。

主要代码

我们的代码基本上有两个主要流程或阶段:

  • 使用基本信息和图像注册狗。
  • 使用新图像执行搜索以在向量数据库中查找狗。

第一阶段:注册小狗

为了存储有关 Luigi 和其他公司的小狗的信息,我们将使用 Dog 类。

为此,我们对序列进行如下的编程:

开始为小狗登记


# Start a connection
es_db = Util.get_connection()
Util.delete_index(es_db, Util.get_index_name())# Register one dog
dog_repo = DogRepository(es_db, Util.get_index_name())
dog_service = DogService(dog_repo)# Visualize the inserted Dog
from IPython.display import display
from IPython.display import Image as ShowImagefilename = "/content/image-search-01/dataset/dogs/Luigi.png"
display(ShowImage(filename=filename, width=300, height=300))

输出:

登记 Luigi

dog = Dog('Luigi', filename, 'Jack Russel/Rat Terrier', 'Ully')dog_service.register_dog(dog)

登记所有其他小狗

import json# JSON data
data = '''
{"dogs": [{"dog_id": "Buddy", "image_path": "", "breed": "Labrador Retriever", "owner_name": "Berlin Red"},{"dog_id": "Bella", "image_path": "", "breed": "German Shepherd", "owner_name": "Tokyo Blue"},{"dog_id": "Charlie", "image_path": "", "breed": "Golden Retriever", "owner_name": "Paris Green"},{"dog_id": "Bigu", "image_path": "", "breed": "Beagle", "owner_name": "Lisbon Yellow"},{"dog_id": "Max", "image_path": "", "breed": "Bulldog", "owner_name": "Canberra Purple"},{"dog_id": "Luna", "image_path": "", "breed": "Poodle", "owner_name": "Wellington Brown"},{"dog_id": "Milo", "image_path": "", "breed": "Rottweiler", "owner_name": "Hanoi Orange"},{"dog_id": "Ruby", "image_path": "", "breed": "Boxer", "owner_name": "Ottawa Pink"},{"dog_id": "Oscar", "image_path": "", "breed": "Dachshund", "owner_name": "Kabul Black"},{"dog_id": "Zoe", "image_path": "", "breed": "Siberian Husky", "owner_name": "Cairo White"}]
}
'''# Convert JSON string to Python dictionary
dogs_data = json.loads(data)# Traverse the list and print dog_id of each dog
image_dogs = "/content/image-search-01/dataset/dogs/"
for dog_info in dogs_data["dogs"]: dog = Dog(dog_info["dog_id"], image_dogs + dog_info["dog_id"] + ".png" , dog_info["breed"], dog_info["owner_name"])dog_service.register_dog(dog)

可视化新狗

# visualize new dogs
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import mathimage_dogs = "/content/image-search-01/dataset/dogs/"
num_dogs = len(dogs_data["dogs"])cols = int(math.sqrt(num_dogs))
rows = int(math.ceil(num_dogs / cols))# Configurar o tamanho da figura
plt.figure(figsize=(5, 5))# Loop para exibir as imagens dos cães
for i, dog_info in enumerate(dogs_data["dogs"]): filename = image_dogs + dog_info["dog_id"] + ".png"img = mpimg.imread(filename)plt.subplot(rows, cols, i+1)  # (número de linhas, número de colunas, índice do subplot)plt.imshow(img)plt.axis('off')plt.show()

输出:

第二阶段:寻找丢失的狗

现在我们已经登记了所有小狗,让我们进行搜索。 我们的开发人员拍了这张丢失小狗的照片。

filename = "/content/image-search-01/dataset/lost-dogs/lost_dog1.png"
display(ShowImage(filename=filename, width=300, height=300))

输出:

看看我们能找到这只可爱的小狗的主人吗?

# find dog by image
result = dog_service.find_dog_by_image(filename)

获取结果

让我们看看我们发现了什么......

filename = result['hits']['hits'][0]['_source']['image_path']
display(ShowImage(filename=filename, width=300, height=300))

输出:

瞧! 我们找到了!!!

但谁将是所有者和他们的名字?

# Print credentials
print(result['hits']['hits'][0]['_source']['dog_id'])
print(result['hits']['hits'][0]['_source']['breed'])
print(result['hits']['hits'][0]['_source']['owner_name'])

输出:

  • Luigi
  • Jack Russel/Rat Terrier
  • Ully

好结局

我们找到了路易吉!!! 我们通知 Ully 吧。

filename = "/content/image-search-01/dataset/lost-dogs/Ully.png"
display(ShowImage(filename=filename, width=300, height=300))

输出:

很快,Ully 和 Luigi 就团聚了。 小狗高兴地摇着尾巴,Ully 紧紧地抱住它,保证再也不会让它离开她的视线。 他们经历了一阵情感旋风,但现在他们在一起了,这才是最重要的。 就这样,Ully 和 Luigi 心中充满了爱和欢乐,从此幸福地生活在一起。

结论

在这篇博文中,我们探索了如何使用 Elasticsearch 通过向量搜索来寻找丢失的小狗。 我们演示了如何生成狗的图像嵌入,在 Elasticsearch 中对其进行索引,然后使用查询图像搜索相似的狗。 该技术可用于寻找丢失的宠物,以及识别图像中其他感兴趣的物体。

向量搜索是一个强大的工具,可用于多种应用。 它特别适合需要根据外观搜索相似对象的任务,例如图像检索和对象识别。

我们希望这篇博文能够提供丰富的信息,并且你会发现我们讨论的技术对你自己的项目很有用。

原文:Finding your puppy with Image Search — Elastic Search Labs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/196133.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VBA如何快速识别Excel单元格中的文本数字

Excel中一种非常特殊的数字,这些数字看似数字,其实是文本格式(下文简称为文本数字),在单元格的左上角会有一个绿色小三角作为标志,如B1:B3单元格。 在编程时为什么需要区分普通数字和文本数字呢&#xff…

什么是Selenium?如何使用Selenium进行自动化测试?

什么是 Selenium? Selenium 是一种开源工具,用于在 Web 浏览器上执行自动化测试(使用任何 Web 浏览器进行 Web 应用程序测试)。   等等,先别激动,让我再次重申一下,Selenium 仅可以测试Web应用…

cvf_使用lora方法增强能力

cvf_使用lora方法增强能力 实验对比图最终代码简介详细解析实验对比图 最终代码 import paddle import numpy as np import pandas as pd from tqdm import tqdmclass FeedFroward(paddle.nn.Layer)

杭州-区块链前瞻性论坛邀请函​

2023密码与安全前瞻性论坛邀请函 生成合法节点或非法节点,测试共识协议

MySQL存储架构

连接管理与安全性 每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询只会在这个线程中执行。MySQL5.5以后支持了一个API叫线程池插件,可以用少量线程服务大量连接,因此不用每次都新建连接然后销毁。 客户端连接MySQL服务器时候&…

不允许你还没有了解哈希表、哈希桶、哈希冲突的解决,如何避免冲突

✏️✏️✏️今天给各位带来的是哈希桶、哈希冲突方面的知识。 清风的CSDN博客 😛😛😛希望我的文章能对你有所帮助,有不足的地方还请各位看官多多指教,大家一起学习交流! 动动你们发财的小手,点…

vscode中Chinese (Simplified)汉化无效解决方法

问题复现 之前已经下载了 Chinese (Simplified)插件并启用了,都是正常的中文简体。有时候打开vscode的时候,会发现汉化失效了,如图: 解决方法 依次点击 扩展(Extensions)— Chinese (Simplified) — 选…

flutter TabBar指示器

第一层tabView import package:jade/configs/PathConfig.dart; import package:jade/customWidget/MyCustomIndicator.dart; importpackage:jade/homePage/promotion/promotionPost/MyPromotionListMainDesc.dart; import package:jade/homePage/promotion/promotionPost/MyPr…

【Nacos】配置管理、微服务配置拉取、实现配置热更新、多环境配置

🐌个人主页: 🐌 叶落闲庭 💨我的专栏:💨 c语言 数据结构 javaEE 操作系统 Redis 石可破也,而不可夺坚;丹可磨也,而不可夺赤。 Nacos 一、nacos实现配置管理1.1 统一配置管…

Windows11 python3.12 安装pyqt6 pyqt6-tools

Windows11 python3.12 安装pyqt6比较容易,但pyqt6-tools一直安装不上去。出错信息如下: (venv) PS D:\python_project\pyqt6> pip install pyqt6-tools Collecting pyqt6-toolsUsing cached pyqt6_tools-6.4.2.3.3-py3-none-any.whl (29 kB) Collec…

cp: can‘t stat ‘/usr/share/zoneinfo/Asia/Shanghai‘: No such file or directory

目录 问题描述问题分析解决方案容器时区验证 问题描述 使用下面的 Dockerfile 为 youlai-boot 项目制作镜像设置容器时区报错。 # 基础镜像 FROM openjdk:17-jdk-alpine # 时区修改 RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \&& echo Asia/Sha…

【图数据库实战】HugeGraph架构

一、概述 作为一款通用的图数据库产品,HugeGraph需具备图数据的基本功能,如下图所示。HugeGraph包括三个层次的功能,分别是存储层、计算层和用户接口层。 HugeGraph支持OLTP和OLAP两种图计算类型,其中OLTP实现了Apache TinkerPop3…

深度学习到智能小车(1)深度学习框架

0.前提 最近新开了一门叫机器学习的课程,老师一直在跟我们讲一些有关这方面的知识,告诉我们一定要学好数学,因为数学是算法的基础。我手上的donkeycar刚好也涉及到Keras深度神经网络,所以出于好奇我去图书馆借回了一本叫《Keras深…

DevSeo Studio设置中文界面

安装好DevSeo Studio后默认打开是欢迎页。 左下角Configure点击展开,选择plugins 弹出页面选择“installed”,然后输入chinese,默认是关闭的,点击enable将它启用,然后点击OK。 弹出页面点击“restart”重启即可。

VS中修改解决方案名称和项目名称

如何修改visual studio2019中的项目名 - 知乎 (zhihu.com) 查了很多,还是这个可行。虽然文中说不是最简单的,但在所查找资料中是可行且最简单的。 要点主要是: 1、比如我们复制一个解决方案,最好是带代码哈,也就是添…

2023.11.18 Hadoop之 YARN

1.简介 Apache Hadoop YARN (Yet Another Resource Negotiator,另一种资源协调者)是一种新的 Hadoop 资源管理器,它是一个通用资源管理系统和调度平台,可为上层应用提供统一的资源管理和调度。支持多个数据处理框架&…

Springboot+vue的学生成绩管理系统(有报告),Javaee项目,springboot vue前后端分离项目。

演示视频: Springbootvue的学生成绩管理系统(有报告),Javaee项目,springboot vue前后端分离项目。 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家…

Docker的3主3从redis集群配置(扩容和缩容配置)

3主3从redis集群配置 1、关闭防火墙启动docker后台服务 systemctl start docker2、新建6个docker容器redis实例 docker run -d --name redis-node-1 --net host --privilegedtrue -v /data/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly …

MatLab的下载、安装与使用(亲测有效)

1、概述 MatLab是由MathWorks公司开发并发布的,支持线性代数、矩阵运算、绘制函数和数据、信号处理、图像处理以及视频处理等功能。广泛用于算法开发、数据可视化、数据分析以及数值计算等。 Matlab 的主要特性包括: 简单易用的语法,使得程…

4-flask-cbv源码、Jinja2模板、请求响应、flask中的session、flask项目参考

1 flask中cbv源码 2 Jinja2模板 3 请求响应 4 flask中的session 5 flask项目参考 1 flask中cbv源码 ***flask的官网文档:***https://flask.palletsprojects.com/en/3.0.x/views/1 cbv源码执行流程1 请求来了,路由匹配成功---》执行ItemAPI.as_view(item…