Skip to content

Commit

Permalink
Pg search: fix broken '*:*' searches, which broke fixing escaping non…
Browse files Browse the repository at this point in the history
…-acceptable search key characters, but inadvertently nuking wildcards. At the same time, this improves the performance of a bare '*:*' search.
  • Loading branch information
ctdk committed Jul 2, 2015
1 parent 3089b64 commit 9eb4796
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 19 deletions.
6 changes: 3 additions & 3 deletions search/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ func (q *BasicQuery) Op() Op {

func (q *BasicQuery) AddField(s Field) {
if config.Config.ConvertSearch {
s = Field(util.PgSearchKey(string(s)))
s = Field(util.PgSearchQueryKey(string(s)))
}
q.field = s
}
Expand Down Expand Up @@ -248,7 +248,7 @@ func (q *GroupedQuery) Op() Op {

func (q *GroupedQuery) AddField(s Field) {
if config.Config.ConvertSearch {
s = Field(util.PgSearchKey(string(s)))
s = Field(util.PgSearchQueryKey(string(s)))
}
q.field = s
}
Expand Down Expand Up @@ -302,7 +302,7 @@ func (q *RangeQuery) Op() Op {

func (q *RangeQuery) AddField(s Field) {
if config.Config.ConvertSearch {
s = Field(util.PgSearchKey(string(s)))
s = Field(util.PgSearchQueryKey(string(s)))
}
q.field = s
}
Expand Down
54 changes: 38 additions & 16 deletions search/postgres_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,46 @@ func (p *PostgresSearch) Search(idx string, q string, rows int, sortOrder string
return nil, serr
}

// keep up with the ersatz solr.
qq := &Tokenizer{Buffer: q}
qq.Init()
if err := qq.Parse(); err != nil {
return nil, err
}
qq.Execute()
qchain := qq.Evaluate()
// Special case "goodness". If the search term is "*:*" with no
// qualifiers, short circuit everything and just get a list of the
// distinct items.
var qresults []string

if q == "*:*" {
logger.Debugf("Searching '*:*' on %s, short circuiting", idx)
sqlStmt := "SELECT COALESCE(ARRAY_AGG(DISTINCT item_name), '{}'::text[]) FROM goiardi.search_items si JOIN goiardi.search_collections sc ON si.search_collection_id = sc.id WHERE si.organization_id = $1 AND sc.name = $2"
var res util.StringSlice
stmt, err := datastore.Dbh.Prepare(sqlStmt)
if err != nil {
return nil, err
}
defer stmt.Close()
err = stmt.QueryRow(1, idx).Scan(&res)
if err != nil && err != sql.ErrNoRows {
return nil, err
}
qresults = res
} else {
// keep up with the ersatz solr.
qq := &Tokenizer{Buffer: q}
qq.Init()
if err := qq.Parse(); err != nil {
return nil, err
}
qq.Execute()
qchain := qq.Evaluate()

pgQ := &PgQuery{idx: idx, queryChain: qchain}
pgQ := &PgQuery{idx: idx, queryChain: qchain}

err := pgQ.execute()
if err != nil {
return nil, err
}
err := pgQ.execute()
if err != nil {
return nil, err
}

qresults, err := pgQ.results()
if err != nil {
return nil, err
qresults, err = pgQ.results()
if err != nil {
return nil, err
}
}
// THE WRONG WAY:
// Eventually, ordering by the keys themselves would be awesome.
Expand All @@ -107,6 +128,7 @@ func (p *PostgresSearch) Search(idx string, q string, rows int, sortOrder string

/* If we're doing partial search, tease out the fields we want. */
if partialData != nil {
var err error
res, err = formatPartials(res, objs, partialData)
if err != nil {
return nil, err
Expand Down
13 changes: 13 additions & 0 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,19 @@ func PgSearchKey(key string) string {
re := regexp.MustCompile(`[^\pL\pN_\.]`)
bs := regexp.MustCompile(`_{2,}`)
ps := regexp.MustCompile(`\.{2,}`) // repeated . will cause trouble too
return pgKeyReplace(key, re, bs, ps)
}

// PgSearchQueryKey is very similar to PgSearchKey, except that it preserves the
// Solr wildcard charactes '*' and '?' in the queries.
func PgSearchQueryKey(key string) string {
re := regexp.MustCompile(`[^\pL\pN_\.\*\?]`)
bs := regexp.MustCompile(`_{2,}`)
ps := regexp.MustCompile(`\.{2,}`)
return pgKeyReplace(key, re, bs, ps)
}

func pgKeyReplace(key string, re, bs, ps *regexp.Regexp) string {
k := re.ReplaceAllString(key, "_")
k = bs.ReplaceAllString(k, "_")
k = ps.ReplaceAllString(k, ".")
Expand Down

0 comments on commit 9eb4796

Please sign in to comment.