use generated columns and gin array indexes to query tags better.

This commit is contained in:
fiatjaf 2022-01-02 17:19:24 -03:00
parent ae3f5df0b9
commit 8091dfedbe
2 changed files with 23 additions and 18 deletions

View File

@ -13,6 +13,12 @@ func initDB(dburl string) (*sqlx.DB, error) {
}
_, err = db.Exec(`
CREATE FUNCTION tags_to_tagvalues(jsonb) RETURNS text[]
AS 'SELECT array_agg(t->>1) FROM (SELECT jsonb_array_elements($1) AS t)s;'
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;
CREATE TABLE IF NOT EXISTS event (
id text NOT NULL,
pubkey text NOT NULL,
@ -20,14 +26,15 @@ CREATE TABLE IF NOT EXISTS event (
kind integer NOT NULL,
tags jsonb NOT NULL,
content text NOT NULL,
sig text NOT NULL
sig text NOT NULL,
tagvalues text[] GENERATED ALWAYS AS (tags_to_tagvalues(tags)) STORED
);
CREATE UNIQUE INDEX IF NOT EXISTS ididx ON event (id);
CREATE UNIQUE INDEX IF NOT EXISTS pubkeytimeidx ON event (pubkey, created_at);
CREATE INDEX IF NOT EXISTS arbitrarytagvalues ON event USING gin (tagvalues);
`)
log.Print(err)
return db, nil
}
const tagConditions = `jsonb_path_match(tags, '$[*][1] == $value', jsonb_build_object('value', ?::text))`

View File

@ -87,40 +87,38 @@ func (b *BasicRelay) QueryEvents(
conditions = append(conditions, `kind IN (`+strings.Join(inkinds, ",")+`)`)
}
tagQuery := make([]string, 0, 1)
if filter.TagE != nil {
if len(filter.TagE) > 10 {
// too many tags, fail everything
return
}
if len(filter.TagE) == 0 {
// #e being [] mean you won't get anything
return
}
innerConditions := make([]string, len(filter.TagE))
for _, e := range filter.TagE {
innerConditions = append(innerConditions, tagConditions)
params = append(params, e)
}
conditions = append(conditions, strings.Join(innerConditions, " OR "))
tagQuery = append(tagQuery, filter.TagE...)
}
if filter.TagP != nil {
if len(filter.TagP) > 10 {
// too many tags, fail everything
return
}
if len(filter.TagP) == 0 {
// #p being [] mean you won't get anything
// #e being [] mean you won't get anything
return
}
innerConditions := make([]string, len(filter.TagP))
for _, p := range filter.TagP {
innerConditions = append(innerConditions, tagConditions)
params = append(params, p)
tagQuery = append(tagQuery, filter.TagP...)
}
if len(tagQuery) > 0 {
arrayBuild := make([]string, len(tagQuery))
for i, tagValue := range tagQuery {
arrayBuild[i] = "?"
params = append(params, tagValue)
}
conditions = append(conditions, strings.Join(innerConditions, " OR "))
conditions = append(conditions,
"tagvalues && ARRAY["+strings.Join(arrayBuild, ",")+"]")
}
if filter.Since != 0 {