Improve performance of account search

This commit is contained in:
Alex Gleason 2025-02-12 14:40:00 -06:00
parent 7d8e5e676c
commit 379953a8cb
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
2 changed files with 34 additions and 33 deletions

View file

@ -119,6 +119,7 @@ const accountSearchQuerySchema = z.object({
const accountSearchController: AppController = async (c) => {
const { signal } = c.req.raw;
const { limit } = c.get('pagination');
const kysely = await Storages.kysely();
const viewerPubkey = await c.get('signer')?.getPublicKey();
@ -136,27 +137,22 @@ const accountSearchController: AppController = async (c) => {
if (!event && lookup) {
const pubkey = await lookupPubkey(lookup);
return c.json(pubkey ? [await accountFromPubkey(pubkey)] : []);
return c.json(pubkey ? [accountFromPubkey(pubkey)] : []);
}
const followedPubkeys: Set<string> = viewerPubkey ? await getFollowedPubkeys(viewerPubkey) : new Set();
const pubkeys = Array.from(await getPubkeysBySearch(kysely, { q: query, limit, offset: 0, followedPubkeys }));
const events: NostrEvent[] = [];
let events = event ? [event] : await store.query([{ kinds: [0], authors: pubkeys, limit }], {
signal,
});
if (!event) {
events = pubkeys
.map((pubkey) => events.find((event) => event.pubkey === pubkey))
.filter((event) => !!event);
if (event) {
events.push(event);
} else {
const following = viewerPubkey ? await getFollowedPubkeys(viewerPubkey) : new Set<string>();
const authors = [...await getPubkeysBySearch(kysely, { q: query, limit, offset: 0, following })];
const profiles = await store.query([{ kinds: [0], authors, limit }], { signal });
events.push(...profiles);
}
const accounts = await hydrateEvents({ events, store, signal }).then(
(events) =>
Promise.all(
events.map((event) => renderAccount(event)),
),
);
const accounts = await hydrateEvents({ events, store, signal })
.then((events) => events.map((event) => renderAccount(event)));
return c.json(accounts);
};

View file

@ -5,30 +5,35 @@ import { DittoTables } from '@/db/DittoTables.ts';
/** Get pubkeys whose name and NIP-05 is similar to 'q' */
export async function getPubkeysBySearch(
kysely: Kysely<DittoTables>,
opts: { q: string; limit: number; offset: number; followedPubkeys: Set<string> },
opts: { q: string; limit: number; offset: number; following: Set<string> },
): Promise<Set<string>> {
const { q, limit, followedPubkeys, offset } = opts;
const { q, limit, following, offset } = opts;
let query = kysely
const pubkeys = new Set<string>();
const query = kysely
.selectFrom('author_stats')
.select((eb) => [
'pubkey',
'search',
eb.fn('word_similarity', [sql`${q}`, 'search']).as('sml'),
])
.where(() => sql`${q} <% search`)
.orderBy(['followers_count desc'])
.orderBy(['sml desc', 'search'])
.select('pubkey')
.where('search', sql`%>`, q)
.orderBy('followers_count desc')
.limit(limit)
.offset(offset);
const pubkeys = new Set((await query.execute()).map(({ pubkey }) => pubkey));
if (following.size) {
const authorsQuery = query.where('pubkey', 'in', [...following]);
if (followedPubkeys.size > 0) {
query = query.where('pubkey', 'in', [...followedPubkeys]);
for (const { pubkey } of await authorsQuery.execute()) {
pubkeys.add(pubkey);
}
}
const followingPubkeys = new Set((await query.execute()).map(({ pubkey }) => pubkey));
if (pubkeys.size >= limit) {
return pubkeys;
}
return new Set(Array.from(followingPubkeys.union(pubkeys)));
for (const { pubkey } of await query.execute()) {
pubkeys.add(pubkey);
}
return pubkeys;
}