Solidity

在智能合約上搜尋數據?

  • February 5, 2020

我有一個智能合約,其中包含一些儲存在結構中的文章數據,該結構用一個 id 進行映射,該 id 用一個映射唯一地標識它,如下所示:

struct Foo {
   string a;
   string b;
}

mapping (uint64 => Foo) public articles;

(顯然上面的程式碼被簡化了,但是結構是一樣的,雖然真正的struct有7個變數而不是2個)。

現在我必須能夠使用 7 個屬性中的任何一個進行搜尋。區塊鏈將是私有的,因此天然氣的使用不是問題。

我的第一個解決方案是在智能合約中添加一個搜尋方法,並在其中遍歷整個映射並檢查哪些項目滿足條件。顯然這是 O(n),2000 個元素大約需要 8 秒,雖然還不錯,但我希望有更好的解決方案。

然後我想有 7 個更多的映射來充當搜尋索引,將每個屬性值映射到滿足它的文章的索引,例如:

mapping (string => uint64) public searchIndex;

(請注意,現在不需要檢查子字元串,只需要檢查相等性)

最後,我在考慮是否將這些索引保留在 Elastic Search 上而不是區塊鏈本身上是否會更好,儘管如果可能的話,我更喜歡純基於區塊鏈的解決方案。

那麼,您認為這些選項(您知道的任何其他更好的選項)中的哪一個更合適?

謝謝你。

很明顯,你不能在不知道它的關鍵的情況下直接得到你想要的對象。7 種映射的想法實際上是最明顯和最不復雜的一種,它在大多數情況下都有效,而不僅僅是你的。

我能想到的最有用的想法是您在結構屬性中尋找模式,這些模式可以幫助您組織搜尋模式,以防您有 10 或 20,000 個元素。例如;如果值與今天和第二天string a的已知時間線相關聯,則另一個條目將具有. 因此,當您想要搜尋結構時,您將更好地了解該結構可能在哪里以及搜尋索引限制是什麼。a == "X12"``a == "X13"``a == X32

因此,搜尋 20000 個元素只需搜尋 2000 個元素。

希望很清楚。

我為解決同一類型的問題所做的一件事是在 Redis 或 Mongo 數據庫中鏡像進入合約的數據,以創建更具可查詢性的數據集。然後,每當我查詢該數據庫時,我都會使用 getter 函式驗證區塊鏈中的數據,以確保它沒有被篡改。我意識到這不是最純粹的僅限區塊鏈的方法,但它的工作原理不會冒大量氣體循環或多個地圖的風險,這些地圖會增加儲存成本,因為應該是對非關鍵屬性的簡單查詢。

鑑於您的簡化契約:

struct Foo {
   string a;
   string b;
}

mapping (uint64 => Foo) public articles;

您可以創建一個事件以在每次創建新添加時發出,這樣返回值和唯一 ID:

event newArticleCreated(string a, string b, index uint64);

然後,使用 Ethers.js 庫(或其他類似 Web3 的庫),您可以設置一個偵聽器來擷取此事件的任何實例並從那里處理您希望的數據。在這種情況下,您可以將數據傳遞給將數據添加到 Mongo 或 Redis 的服務,其中密鑰是契約中的 uint64 密鑰:

   //import the ethers.js library
   const ethers = require('ethers');

   //set your provider and create a new instance of your contract by providing 
   //the ABI and deployed address 
   let provider = new ethers.providers.JsonRpcProvider(<RPC URL for your node>); 
   contractInstance = new ethers.Contract(<contractAddress>, <abi>, provider);

   //listen for events matching this name
   contractInstance.on("newArticleCreated", (a, b, index) => {
       //do stuff when the event fires

       //set the values in the event to a JSON object structure
       let chainObj = {
           id: index, 
           a: a
           b: b
       }

       //add the data to the database
       dataService.addDataToDatabase(chainObj);

我個人在這種設置方面取得了成功,它具有很大的靈活性。它允許您查詢從鏈中鏡像的數據,但始終使用該索引/唯一 ID 與合約驗證該數據。

謝謝!

引用自:https://ethereum.stackexchange.com/questions/39825