Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/recommendations #265

Merged
merged 13 commits into from
Apr 14, 2022
Merged
246 changes: 246 additions & 0 deletions src/pocketdb/repositories/web/SearchRepository.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -730,4 +730,250 @@ namespace PocketDb

return result;
}

vector<string> SearchRepository::GetRecommendedAccountByAddressSubscriptions(const string& address, string& addressExclude, const vector<int>& contentTypes, const string& lang, int cntOut, int nHeight, int depth, int cntSubscriptions)
{
auto func = __func__;
vector<string> ids;

if (address.empty())
return ids;

string contentTypesFilter = join(vector<string>(contentTypes.size(), "?"), ",");

string excludeAddressFilter = "?";
if (!addressExclude.empty())
excludeAddressFilter += ", ?";

string langFilter = "";
if (!lang.empty())
langFilter = "cross join Payload lang on lang.TxHash = u.Hash and lang.String1 = ?";

int minReputation = 30;

string sql = R"sql(
select Contents.String1
from Transactions Rates indexed by Transactions_Type_Last_String1_Height_Id
cross join Transactions Contents indexed by Transactions_Type_Last_String2_Height
on Contents.String2 = Rates.String2
and Contents.Last = 1
and Contents.Height > 0
and Contents.Type in ( )sql" + contentTypesFilter + R"sql( )
and Contents.String1 not in ( ? )
cross join Transactions u indexed by Transactions_Type_Last_String1_Height_Id
on u.String1 = Contents.String1
and u.Type in (100)
and u.Last = 1
and u.Height > 0
)sql" + langFilter + R"sql(
where Rates.Type in (300)
and Rates.Int1 = 5
and Rates.Height > ?
and Rates.Last in (0, 1)
and Rates.String1 in (
select subscribes.String2
from Transactions subscribes indexed by Transactions_Type_Last_String1_Height_Id
where subscribes.Type in (302, 303)
and subscribes.Last = 1
and subscribes.Height > 0
and subscribes.String1 = ?
limit ?
)
group by Contents.String1
having count(*) > 1
order by count (*) desc
limit ?
)sql";

TryTransactionStep(__func__, [&]()
{
auto stmt = SetupSqlStatement(sql);

int i = 1;
for (const auto& contenttype: contentTypes)
TryBindStatementInt(stmt, i++, contenttype);

TryBindStatementText(stmt, i++, address);
if (!addressExclude.empty())
TryBindStatementText(stmt, i++, addressExclude);

if (!lang.empty())
TryBindStatementText(stmt, i++, lang);

TryBindStatementInt(stmt, i++, nHeight-depth);

TryBindStatementText(stmt, i++, address);

TryBindStatementInt(stmt, i++, cntSubscriptions);

TryBindStatementInt(stmt, i++, cntOut);

while (sqlite3_step(*stmt) == SQLITE_ROW)
{
if (auto[ok, value] = TryGetColumnString(*stmt, 0); ok)
ids.push_back(value);
}

FinalizeSqlStatement(*stmt);
});

return ids;
}

vector<int64_t> SearchRepository::GetRecommendedContentByAddressSubscriptions(const string& contentAddress, string& address, const vector<int>& contentTypes, const string& lang, int cntOut, int nHeight, int depth, int cntSubscriptions)
{
auto func = __func__;
vector<int64_t> ids;

if (contentAddress.empty())
return ids;

string contentTypesFilter = join(vector<string>(contentTypes.size(), "?"), ",");

string excludeAddressFilter = "?";
if (!address.empty())
excludeAddressFilter += ", ?";

string langFilter = "";
if (!lang.empty())
langFilter = "cross join Payload lang on lang.TxHash = Contents.Hash and lang.String1 = ?";

int minReputation = 30;

string sql = R"sql(
select recomendations.Id
from (
select Contents.String1,
Contents.Id,
Rates.String2,
count(*) count
from Transactions Rates indexed by Transactions_Type_Last_String1_Height_Id
cross join Transactions Contents indexed by Transactions_Type_Last_String2_Height
on Contents.String2 = Rates.String2
and Contents.Last = 1
and Contents.Height > 0
and Contents.Type in ( )sql" + contentTypesFilter + R"sql( )
and Contents.String1 not in ( )sql" + excludeAddressFilter + R"sql( )
)sql" + langFilter + R"sql(
where Rates.Type in (300)
and Rates.Int1 = 5
and Rates.Height > ?--0
and Rates.Last in (0, 1)
and Rates.String1 in (
select subscribers.String2
from Transactions subscribers indexed by Transactions_Type_Last_String1_Height_Id
cross join Transactions u indexed by Transactions_Type_Last_String1_Height_Id
on u.Type in (100)
and u.Last = 1 and u.Height > 0
and u.String1 = subscribers.String1
cross join Ratings r indexed by Ratings_Type_Id_Last_Value
on r.Id = u.Id
and r.Type = 0
and r.Last = 1
and r.Value > ?
where subscribers.Type in (302, 303)
and subscribers.Last = 1
and subscribers.Height > 0
and subscribers.String1 = ?
limit ?
)
group by Rates.String2
having count(*) > 1
order by count(*) desc
) recomendations
group by recomendations.String1
limit ?
)sql";

TryTransactionStep(__func__, [&]()
{
auto stmt = SetupSqlStatement(sql);

int i = 1;
for (const auto& contenttype: contentTypes)
TryBindStatementInt(stmt, i++, contenttype);

TryBindStatementText(stmt, i++, contentAddress);
if (!address.empty())
TryBindStatementText(stmt, i++, address);

if (!lang.empty())
TryBindStatementText(stmt, i++, lang);

TryBindStatementInt(stmt, i++, nHeight-depth);

TryBindStatementInt(stmt, i++, minReputation);
TryBindStatementText(stmt, i++, contentAddress);

TryBindStatementInt(stmt, i++, cntSubscriptions);

TryBindStatementInt(stmt, i++, cntOut);

while (sqlite3_step(*stmt) == SQLITE_ROW)
{
if (auto[ok, value] = TryGetColumnInt64(*stmt, 0); ok)
ids.push_back(value);
}

FinalizeSqlStatement(*stmt);
});

return ids;
}

vector<int64_t> SearchRepository::GetRandomContentByAddress(const string& contentAddress, const vector<int>& contentTypes, const string& lang, int cntOut)
{
auto func = __func__;
vector<int64_t> ids;

if (contentAddress.empty())
return ids;

string contentTypesFilter = join(vector<string>(contentTypes.size(), "?"), ",");

string langFilter = "";
if (!lang.empty())
langFilter = "cross join Payload lang on lang.TxHash = Contents.Hash and lang.String1 = ?";

string sql = R"sql(
select Contents.Id
from Transactions Contents indexed by Transactions_Type_Last_String1_Height_Id
)sql" + langFilter + R"sql(
where Contents.Type in ( )sql" + contentTypesFilter + R"sql( )
and Contents.Last = 1
and Contents.String1 = ?
and Contents.Height > 0
order by random()
limit ?
)sql";

TryTransactionStep(__func__, [&]()
{
auto stmt = SetupSqlStatement(sql);

int i = 1;

if (!lang.empty())
TryBindStatementText(stmt, i++, lang);

for (const auto& contenttype: contentTypes)
TryBindStatementInt(stmt, i++, contenttype);

TryBindStatementText(stmt, i++, contentAddress);

TryBindStatementInt(stmt, i++, cntOut);

while (sqlite3_step(*stmt) == SQLITE_ROW)
{
if (auto[ok, value] = TryGetColumnInt64(*stmt, 0); ok)
ids.push_back(value);
}

FinalizeSqlStatement(*stmt);
});

return ids;


}
}
4 changes: 4 additions & 0 deletions src/pocketdb/repositories/web/SearchRepository.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ namespace PocketDb
UniValue GetRecomendedAccountsByTags(const vector<string>& tags, int nHeight, int depth = 1000, int cntOut = 10);
UniValue GetRecomendedContentsByScoresOnSimilarContents(const string& contentid, const vector<int>& contentTypes, int depth = 1000, int cntOut = 10);
UniValue GetRecomendedContentsByScoresFromAddress(const string& address, const vector<int>& contentTypes, int nHeight, int depth = 1000, int cntOut = 10);

vector<string> GetRecommendedAccountByAddressSubscriptions(const string& address, string& addressExclude, const vector<int>& contentTypes, const string& lang, int cntOut, int nHeight, int depth = 129600 /* about 3 month */, int cntSubscriptions = 100);
vector<int64_t> GetRecommendedContentByAddressSubscriptions(const string& contentAddress, string& address, const vector<int>& contentTypes, const string& lang, int cntOut, int nHeight, int depth = 129600 /* about 3 month */, int cntSubscriptions = 100);
vector<int64_t> GetRandomContentByAddress(const string& contentAddress, const vector<int>& contentTypes, const string& lang, int cntOut);
};

typedef shared_ptr<SearchRepository> SearchRepositoryRef;
Expand Down
Loading