aboutsummaryrefslogtreecommitdiff
path: root/internal/postgres
diff options
context:
space:
mode:
authorJulie Qiu <julie@golang.org>2021-07-17 16:30:53 -0400
committerJulie Qiu <julie@golang.org>2021-07-20 13:21:56 +0000
commit685af85aeb4e043f458dfed28947e8ef2dbb285e (patch)
tree3a8042a71688adc5d6b901f528edd133f7a7cd1b /internal/postgres
parent50446a6eb602460b5b27bb0976012ead8e6d32e7 (diff)
downloadgo-x-pkgsite-685af85aeb4e043f458dfed28947e8ef2dbb285e.tar.xz
internal/postgres/{symbolsearch}: add QueryPackageDotSymbol
QueryPackageDotSymbol is added, which is used when the search input is one word, contains one dot, and we assume that it has the structure <package>.<symbol>. For golang/go#44142 Change-Id: Ie08b32e9cbfba709aceed82dd9c3bde2bc22cfdc Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/335234 Trust: Julie Qiu <julie@golang.org> Run-TryBot: Julie Qiu <julie@golang.org> TryBot-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: Jonathan Amsterdam <jba@google.com>
Diffstat (limited to 'internal/postgres')
-rw-r--r--internal/postgres/symbolsearch.go40
-rw-r--r--internal/postgres/symbolsearch/gen_query.go9
-rw-r--r--internal/postgres/symbolsearch/query.gen.go52
-rw-r--r--internal/postgres/symbolsearch/symbolsearch.go32
-rw-r--r--internal/postgres/symbolsearch_test.go9
5 files changed, 125 insertions, 17 deletions
diff --git a/internal/postgres/symbolsearch.go b/internal/postgres/symbolsearch.go
index 0c82331b..48b72afc 100644
--- a/internal/postgres/symbolsearch.go
+++ b/internal/postgres/symbolsearch.go
@@ -8,6 +8,7 @@ import (
"context"
"database/sql"
"fmt"
+ "strings"
"github.com/lib/pq"
"golang.org/x/pkgsite/internal"
@@ -111,15 +112,38 @@ func (db *DB) symbolSearch(ctx context.Context, q string, limit, offset, maxResu
return nil
}
- // TODO: add additional queries based on q.
- query := symbolsearch.QuerySymbol
- err := db.db.RunQuery(ctx, query, collect, q, limit, offset)
- if err != nil {
- results = nil
+ var (
+ query string
+ err error
+ )
+ if len(strings.Fields(q)) == 1 {
+ switch len(strings.Split(q, ".")) {
+ case 1:
+ // There is only 1 word in the search, and there are no dots, so
+ // this must be the symbol name.
+ query = symbolsearch.QuerySymbol
+ case 2:
+ // There is only 1 element, split by 1 dot, so the search must
+ // either be for <package>.<symbol> or <type>.<methodOrFieldName>.
+ // TODO: implement
+ case 3:
+ // There is only 1 element, split by 2 dots, so the search must
+ // be for <package>.<type>.<methodOrFieldName>.
+ query = symbolsearch.QueryPackageDotSymbol
+ }
+ } else {
+ // TODO: add additional queries based on q.
+ err = fmt.Errorf("unsupported query structure: %q", q)
}
- if len(results) > 0 && results[0].NumResults > uint64(maxResultCount) {
- for _, r := range results {
- r.NumResults = uint64(maxResultCount)
+ if err == nil {
+ err = db.db.RunQuery(ctx, query, collect, q, limit, offset)
+ if err != nil {
+ results = nil
+ }
+ if len(results) > 0 && results[0].NumResults > uint64(maxResultCount) {
+ for _, r := range results {
+ r.NumResults = uint64(maxResultCount)
+ }
}
}
return searchResponse{
diff --git a/internal/postgres/symbolsearch/gen_query.go b/internal/postgres/symbolsearch/gen_query.go
index f0969ab2..9c5b58aa 100644
--- a/internal/postgres/symbolsearch/gen_query.go
+++ b/internal/postgres/symbolsearch/gen_query.go
@@ -45,7 +45,14 @@ package symbolsearch
// QuerySymbol is used when the search query is only one word, with no dots.
// In this case, the word must match a symbol name and ranking is completely
// determined by the path_tokens.
-%s`, formatQuery("QuerySymbol", symbolsearch.RawQuerySymbol))
+%s
+
+// QueryPackageDotSymbol is used when the search query is one element
+// containing a dot, where the first part is assumed to be the package name and
+// the second the symbol name. For example, "sql.DB" or "sql.DB.Begin".
+%s`,
+ formatQuery("QuerySymbol", symbolsearch.RawQuerySymbol),
+ formatQuery("QueryPackageDotSymbol", symbolsearch.RawQueryPackageDotSymbol))
func formatQuery(name, query string) string {
return fmt.Sprintf("const %s = `%s`", name, query)
diff --git a/internal/postgres/symbolsearch/query.gen.go b/internal/postgres/symbolsearch/query.gen.go
index 8ae4d235..6cf98fb4 100644
--- a/internal/postgres/symbolsearch/query.gen.go
+++ b/internal/postgres/symbolsearch/query.gen.go
@@ -57,3 +57,55 @@ ORDER BY
package_path
LIMIT $2
OFFSET $3;`
+
+// QueryPackageDotSymbol is used when the search query is one element
+// containing a dot, where the first part is assumed to be the package name and
+// the second the symbol name. For example, "sql.DB" or "sql.DB.Begin".
+const QueryPackageDotSymbol = `
+WITH results AS (
+ SELECT
+ s.name AS symbol_name,
+ sd.package_path,
+ sd.module_path,
+ sd.version,
+ sd.name AS package_name,
+ sd.synopsis,
+ sd.license_types,
+ sd.commit_time,
+ sd.imported_by_count,
+ ssd.package_symbol_id,
+ ssd.goos,
+ ssd.goarch,
+ (ln(exp(1)+imported_by_count)
+ * CASE WHEN sd.redistributable THEN 1 ELSE 0.500000 END
+ * CASE WHEN COALESCE(has_go_mod, true) THEN 1 ELSE 0.800000 END) AS score
+ FROM symbol_search_documents ssd
+ INNER JOIN search_documents sd ON sd.unit_id = ssd.unit_id
+ INNER JOIN symbol_names s ON s.id = ssd.symbol_name_id
+ WHERE sd.name = split_part($1, '.', 1) AND s.tsv_name_tokens @@ to_tsquery('symbols', substring(replace($1, '_', '-') from E'[^.]*\.(.+)$'))
+)
+SELECT
+ r.package_path,
+ r.module_path,
+ r.version,
+ r.package_name,
+ r.synopsis,
+ r.license_types,
+ r.commit_time,
+ r.imported_by_count,
+ r.symbol_name,
+ r.goos,
+ r.goarch,
+ ps.type AS symbol_type,
+ ps.synopsis AS symbol_synopsis,
+ COUNT(*) OVER() AS total
+FROM results r
+INNER JOIN package_symbols ps ON r.package_symbol_id = ps.id
+WHERE r.score > 0.1
+ORDER BY
+ score DESC,
+ commit_time DESC,
+ symbol_name,
+ package_path
+LIMIT $2
+OFFSET $3;`
diff --git a/internal/postgres/symbolsearch/symbolsearch.go b/internal/postgres/symbolsearch/symbolsearch.go
index dbba7d88..0229a385 100644
--- a/internal/postgres/symbolsearch/symbolsearch.go
+++ b/internal/postgres/symbolsearch/symbolsearch.go
@@ -19,15 +19,35 @@ import (
const SymbolTextSearchConfiguration = "symbols"
-var RawQuerySymbol = fmt.Sprintf(symbolSearchBaseQuery, scoreSymbol, filterSymbol)
+var (
+ RawQuerySymbol = fmt.Sprintf(symbolSearchBaseQuery, scoreMultipliers, filterSymbol)
+ RawQueryPackageDotSymbol = fmt.Sprintf(symbolSearchBaseQuery, scoreMultipliers, filterPackageDotSymbol)
+)
-// filterSymbol is used when $1 is the full symbol name, either
-// <symbol> or <type>.<methodOrField>.
-var filterSymbol = fmt.Sprintf(`s.tsv_name_tokens @@ %s`, toTSQuery("$1"))
+var (
+ // filterSymbol is used when $1 is the full symbol name, either
+ // <symbol> or <type>.<methodOrField>.
+ filterSymbol = fmt.Sprintf(`s.tsv_name_tokens @@ %s`, toTSQuery("$1"))
+
+ // filterPackageDotSymbol is used when $1 is either <package>.<symbol> OR
+ // <package>.<type>.<methodOrField>.
+ filterPackageDotSymbol = fmt.Sprintf(
+ // Split the package name from $1, which can be assumed to be the
+ // element preceding the first dot.
+ `sd.name = split_part($1, '.', 1) AND s.tsv_name_tokens @@ %s`,
+ // Split the symbol name from $1, which can be assumed to be everything
+ // following the first dot.
+ toTSQuery("substring($1 from E'[^.]*\\.(.+)$')"))
+)
var (
- // scoreSymbol is the score the for QuerySymbol.
- scoreSymbol = fmt.Sprintf("%s\n\t\t* %s\n\t\t* %s",
+ // scoreMultipliers is the score of multiplying the multiplers.
+ //
+ // It is also used as the score for QuerySymbol and QueryPackageDotIdentifier.
+ // In both cases, the matching symbols will be filtered in the WHERE
+ // clause, and the only remaining information to rank the results by are
+ // the multiplers.
+ scoreMultipliers = fmt.Sprintf("%s\n\t\t* %s\n\t\t* %s",
popularityMultiplier, redistributableMultipler, goModMultipler)
// Popularity multipler to increase ranking of popular packages.
diff --git a/internal/postgres/symbolsearch_test.go b/internal/postgres/symbolsearch_test.go
index e97f19d9..b82e37f6 100644
--- a/internal/postgres/symbolsearch_test.go
+++ b/internal/postgres/symbolsearch_test.go
@@ -52,15 +52,20 @@ func TestSymbolSearch(t *testing.T) {
want []*SearchResult
}{
{
- name: "test search by <identifier>",
+ name: "test search by <symbol>",
q: sample.Variable.Name,
want: checkResult(sample.Variable.SymbolMeta),
},
{
- name: "test search by <recv>",
+ name: "test search by <methodName>",
q: "Method",
want: checkResult(sample.Method),
},
+ {
+ name: "test search by <package>.<type>.<methodName>",
+ q: "foo.Type.Method",
+ want: checkResult(sample.Method),
+ },
/*
{
name: "test search by <package>.<identifier>",