Поиск данных по смарт-контракту?

У меня есть смарт-контракт, который содержит некоторые данные статьи, хранящиеся внутри структуры, которая сопоставляется с идентификатором, который однозначно идентифицирует ее с помощью сопоставления, например:

struct Foo {
    string a;
    string b;
}

mapping (uint64 => Foo) public articles;

(Очевидно, что приведенный выше код упрощен, но структура такая же, хотя реальная структура имеет 7 переменных вместо 2).

Теперь я должен иметь возможность искать, используя любой из 7 атрибутов. Блокчейн будет частным, поэтому использование газа не будет проблемой.

Мое первое решение состояло в том, чтобы добавить в смарт-контракт метод поиска и внутри него пройти все сопоставление и проверить, какие элементы удовлетворяют условию. Очевидно, что это O(n), и для 2000 элементов потребовалось около 8 секунд, что, хотя и неплохо, надеюсь на лучшее решение.

Затем я подумал о том, чтобы иметь еще 7 сопоставлений, которые будут действовать как поисковые индексы, сопоставляя каждое значение атрибута с индексом статьи, которая его удовлетворяет, например:

mapping (string => uint64) public searchIndex;

(Обратите внимание, что сейчас не требуется проверять подстроки, только равенство)

И, наконец, я подумал о том, было бы хорошо хранить эти индексы в Elastic Search, а не в самой цепочке блоков, хотя я бы предпочел, если это возможно, чистое решение на основе цепочки блоков.

Итак, какой из этих вариантов (из любых других, которые вам лучше известны) вы считаете более адекватным?

Спасибо.

Интересна ли эта поисковая система смарт-контрактов с открытым исходным кодом и M2M API? blog.secondstate.io/post/20190703-search-engine-обзор ethereum.search.secondstate.io

Ответы (2)

Понятно, что вы не можете напрямую получить нужный объект, не зная его ключа. Идея 7 отображений на самом деле самая очевидная и наименее сложная, и она работает в большинстве случаев не только у вас.

Самая полезная идея, которую я могу предложить, заключается в том, что вы ищете шаблоны в атрибутах вашей структуры, шаблоны, которые помогают вам организовать схему поиска, если у вас есть 10 или 20 тысяч элементов. например ; если string aзначения связаны с известной временной шкалой, например, a == "X12"сегодня и на следующий день, другая запись будет иметь a == "X13". Поэтому, когда вы захотите искать структуры, у a == X32вас будет лучшее понимание того, где может быть эта структура и каковы ограничения поискового индекса.

Таким образом, делая поиск по 20 тысячам элементов поиском всего по 2 тысячам.

надеюсь было понятно.

Одна вещь, которую я сделал, чтобы решить эту же проблему, — это отразить данные, поступающие в контракт, в базу данных Redis или Mongo, чтобы создать гораздо более доступный для запросов набор данных. Затем, всякий раз, когда я запрашиваю эту базу данных, я проверяю данные в блокчейне с помощью функции получения, чтобы убедиться, что они не были подделаны. Я понимаю, что это не самый чистый метод только для блокчейна, но он работает, не рискуя зациклиться на газе или множественных карт, которые умножают стоимость хранения для того, что должно быть простыми запросами по неключевым атрибутам.

Учитывая ваш упрощенный контракт:

struct Foo {
    string a;
    string b;
}

mapping (uint64 => Foo) public articles;

Вы можете создать событие, которое будет генерироваться всякий раз, когда создается новое дополнение, подобное этому, которое возвращает значения и уникальный идентификатор:

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);

Я лично добился успеха с этим типом настройки, и он обладает большой гибкостью. Это позволяет вам запрашивать данные, зеркально отраженные в цепочке, но всегда проверять эти данные обратно с контрактом, используя этот индекс/уникальный идентификатор.

Спасибо!