milvus是幹什麼的?通俗的講,milvus可讓你在海量向量庫中快速檢索到和目標向量最類似的若干個向量,這裏類似度量標準能夠是內積或者歐式距離等。借用官方的話說就是:html
Milvus 是一款開源的、針對海量特徵向量的類似性搜索引擎。基於異構衆覈計算框架設計,成本更低,性能更好。 在有限的計算資源下,十億向量搜索僅毫秒響應。java
說白了就是速度快,先不說十億向量,本身寫代碼去完成對100萬300維向量的餘弦類似度計算並排序就須要不小的響應時間吧,就本人測試而言,即使使用scipy庫計算速度依然要比milvus慢不少。python
其實在milvus開源以前,也存在高性能向量類似性搜索引擎(庫),這個引擎就是Facebook的Faiss,它的功能和milvus是同樣的,因此就再也不作過多介紹,具體能夠參考官網linux
就我我的而言,我是推薦使用milvus的,主要是在我我的看來,milvus有以下幾個好處:c++
固然milvus也有難用的地方,我本身發現了兩點,若是是我本身使用不當形成的,還請各位朋友在評論指出:git
milvus 一共有兩種安裝方式:本身編譯安裝和使用docker安裝。這裏推薦你們使用docker安裝,docker安裝方便快捷,可在Windows上使用。本身編譯安裝,因爲每一個人環境不一樣,很容易出問題。本文只介紹基於docker的安裝,另外由於我比較窮,因此只介紹cpu版本的安裝,不過gpu安裝也是大同小異。github
簡言之安裝比較簡單,畢竟大佬們已經把milvus部署在了docker裏,咱們只要啓動起來就好了
。docker
首先就是要安裝docker,還不瞭解docker能夠了解一波,很是好用的虛擬機工具,直接去官網下載對應平臺的安裝文件便可。數據庫
安裝好docker後,要去pull對應的鏡像(image),首先進到dockerhub官網中,而後搜索milvus,第一個結果就是。由於咱們安裝的是CPU版本,因此在tags裏找cpu-latest,而後pull下來就能夠了,即在你的命令行窗口輸入
docker pull milvusdb/milvus:cpu-latest
。注意:隨着版本迭代更新,這一條命令在將來可能會失效,建議先去dockerhub搜索一下,去看一下應該用什麼tag。編程
在建立啓動容器以前,咱們要先設置好工做目錄和配置文件。
一共要設置三個目錄,分別是數據庫存儲目錄,日誌存儲目錄和配置文件目錄。其中配置文件目錄就存放着我說的配置文件。配置文件一共有兩個,分別是服務器設置文件和日誌設置文件。
因此咱們要想好這三個文件夾放在哪裏,好比咱們能夠在當前用戶目錄下創建一個milvus文件夾,而後在這裏面存儲上述三個目錄。下面咱們須要設置兩個配置文件,記得要把服務器配置文件名改成server_config.yaml,把日誌配置文件改成log_config.conf。
兩個配置文件的內容:服務器配置文件 日誌配置文件。配置文件也能夠到官網下載。
下面是個人文件目錄結構,共你們參考:
milvus │ ├─conf //配置文件目錄 │ log_config.conf //服務器配置文件 │ server_config.yaml //日誌配置文件 │ ├─db //數據庫存儲目錄 │ └─logs //日誌存儲目錄 │
設置好工做目錄後,就可使用鏡像建立容器了,個人工做目錄是C:\Users\Zhdun\milvus
,因此個人建立命令是:
docker run -td --name mymilvus -e "TZ=Asia/Shanghai" -p 19530:19530 -p 8080:8080 -v C:\Users\Zhdun\milvus\db:/var/lib/milvus/db -v C:\Users\Zhdun\milvus\conf:/var/lib/milvus/conf -v C:\Users\Zhdun\milvus\logs:/var/lib/milvus/logs milvusdb/milvus:cpu-latest
命令看起來有點長, 我稍微解釋下,-td是後臺運行,--name是給本身的容器起個名字,-p是端口映射,不想用默認的話,能夠去服務器配置文件裏改,-v就是爲了映射三個工做目錄。具體能夠參考docker的run命令。
執行完命令後,運行docker ps -a,若是發現本身建立的容器excited的了,那就docker logs一下,看出了什麼問題。若是發現容器在運行了,就表明基本沒問題了。
接下來我會說一下常見的安裝問題,以及如何去使用milvus。
Config check fail: Invalid config version: . Expected config version: 0.1 遇到這種問題就在服務器的配置文件第一行加上version: 0.1
。
Config check fail: Invalid cpu cache capacity: 1. Possible reason: sum of cache_config.cpu_cache_capacity and db_config.insert_buffer_size exceeds system memory.
這種問題就說明內存超出了限制,首先檢查服務器配置裏的 cpu_cache_capacity 和 insert_buffer_size 是否是過大了。
而後再檢查給定docker設定的內存是多少,能夠經過docker info來檢查。
安裝完成後,終於能夠開始使用milvus了,milvus支持python,java和c++。在這裏我只介紹python的使用。
首先安裝 pymilvus庫:pip install pymilvus
,而後就可使用這個庫來寫代碼了,接下來我會直接把本身寫的範例代碼貼上去,其中每一步的具體含義以及可能的擴展我會直接在註釋裏告訴你們,若有錯誤還請各位指出。
# -*- coding: utf-8 -*- #導入相應的包 import numpy as np from milvus import Milvus, IndexType, MetricType # 初始化一個Milvus類,之後全部的操做都是經過milvus來的 milvus = Milvus() # 鏈接到服務器,注意端口映射,要和啓動docker時設置的端口一致 milvus.connect(host='localhost', port='19530') # 向量個數 num_vec = 5000 # 向量維度 vec_dim = 768 # 建立表 # 參數含義 # table_name: 表名 # dimension: 向量維度 # metric_type: 向量類似度度量標準, MetricType.IP是向量內積; MetricType.L2是歐式距離 table_param = {'table_name': 'mytable', 'dimension':vec_dim, 'index_file_size':1024, 'metric_type':MetricType.IP} milvus.create_table(table_param) # 隨機生成一批向量數據 vectors_array = np.random.rand(num_vec,vec_dim) vectors_list = vectors_array.tolist() # 官方建議在插入向量以前,建議先使用 milvus.create_index 以便系統自動增量建立索引 # 索引類型有:FLAT / IVFLAT / IVF_SQ8 / IVF_SQ8H,其中FLAT是精確索引,速度慢,可是有100%的召回率 index_param = {'index_type': IndexType.FLAT, 'nlist': 128} milvus.create_index('mytable', index_param) # 把向量添加到剛纔創建的表格中 # ids能夠爲None,使用自動生成的id status, ids = milvus.add_vectors(table_name="mytable",records=vectors_list,ids=None) # 返回這一組向量的ID # 官方建議 向量插入結束後,相同的索引須要手動再建立一次 milvus.create_index('mytable', index_param) # 輸出一些統計信息 status, tables = milvus.show_tables() print("全部的表格:",tables) print("表格的數據量(行):{}".format((milvus.count_table('mytable')[1]))) print("mytable表格是否存在:",milvus.has_table("mytable")[1]) # 加載表格到內存 milvus.preload_table('mytable') # 建立查詢向量 query_vec_array = np.random.rand(1,vec_dim) query_vec_list = query_vec_array.tolist() # 進行查詢, 注意這裏的參數nprobe和創建索引時的參數nlist 會由於索引類型不一樣而影響到查詢性能和查詢準確率 # 對於 FLAT類型索引,兩個參數對結果和速度沒有影響 status, results = milvus.search(table_name='mytable', query_records=query_vec_list, top_k=4, nprobe=16) print(status) print(results) # 刪除表格和索引, 不刪除的話,下一次還能夠繼續使用 milvus.drop_index(table_name="mytable") milvus.delete_table(table_name="mytable") # 斷開鏈接 milvus.disconnect()
寫這一章的主要目的是爲了進行併發測試,以及多進程可否節省時間,官方說明在使用多進程時須要知足下面兩個條件:
- 程序執行時主進程中沒有建立 client
- 每一個子進程分別建立 client 進行操做
下面是個人測試代碼:
# -*- coding: utf-8 -*- import time from multiprocessing import Pool import numpy as np import random from milvus import Milvus, IndexType, MetricType def create_data(host,port,num_vec,vec_dim): """ 建立一些表格和索引用來作多進程測試 """ milvus = Milvus() milvus.connect(host=host, port=port) # 建立2個表 table_param = {'table_name': 'table1', 'dimension':vec_dim, 'index_file_size':1024, 'metric_type':MetricType.IP} milvus.create_table(table_param) table_param = {'table_name': 'table2', 'dimension':vec_dim, 'index_file_size':1024, 'metric_type':MetricType.L2} milvus.create_table(table_param) # 隨機生成一批向量數據 vectors_array = np.random.rand(num_vec,vec_dim) vectors_list = vectors_array.tolist() # 建立索引 index_param = {'index_type': IndexType.FLAT, 'nlist': 128} milvus.create_index('table1', index_param) milvus.create_index('table2', index_param) # 添加數據 milvus.add_vectors(table_name="table1",records=vectors_list,ids=None) milvus.add_vectors(table_name="table2",records=vectors_list,ids=None) # 建立索引 milvus.create_index('table1', index_param) milvus.create_index('table2', index_param) print(milvus.show_tables()) # 斷開鏈接 milvus.disconnect() def clear_table(host,port): """ 清空表格和索引 """ milvus = Milvus() milvus.connect(host=host, port=port) for table_name in milvus.show_tables()[1]: milvus.drop_index(table_name=table_name) milvus.delete_table(table_name=table_name) milvus.disconnect() def milvus_search(host,port,table_name,query_vec,search_time=10): """ 測試查詢, 返回查詢的秒數""" milvus = Milvus() milvus.connect(host=host, port=port) # 由於bug的緣由,要先搜索一次 milvus.search(table_name,4,8,query_vec) # 開始測試 for _ in range(search_time): query_vec[0][0] = random.random() # 稍微隨機化一下 milvus.search(table_name, 4, 8, query_vec) if __name__ == "__main__": host = "localhost" port = "19530" num_vec = 100000 vec_dim = 768 num_proc = 3 # 進程數 search_time = 2000 # 搜索次數 ####### Step1 先建立用於測試的數據 運行一次就好了 # create_data(host=host,port=port,num_vec=num_vec,vec_dim=vec_dim) # clear_table(host,port) # exit(0) ####### Step2 測試依次執行的時間 start_time = time.time() for _ in range(num_proc): query_vec = np.random.rand(1,vec_dim).tolist() milvus_search(host,port,"table1",query_vec,search_time) end_time = time.time() print("順序執行milvus_search的時間總和是:",end_time-start_time) ####### Step3 測試多進程時間 pool = Pool(num_proc) start_time = time.time() for _ in range(num_proc): query_vec = np.random.rand(1,vec_dim).tolist() pool.apply_async(milvus_search,args=(host,port,"table1",query_vec,search_time)) pool.close() pool.join() end_time = time.time() print("並行執行milvus_search的時間總和是:",end_time-start_time)
結論就是對於search操做,依次search100次,和10個進程同時開,每一個進程search10次,開多進程速度是會變快的。個人理解和結論比較膚淺,但願你們批評指正。
感謝你們閱讀,但願能幫助到大家一些。若是寫的有什麼問題,還請各位指出。
文章能夠隨意轉載,但請務必註明出處: