Skip to content

Commit

Permalink
Merge pull request #16 from unisoncomputing/cp/search-names-prefix
Browse files Browse the repository at this point in the history
Switch name search to return suffixes of prefixes.
  • Loading branch information
ChrisPenner authored Jul 29, 2024
2 parents 0aeb41d + d10bc48 commit f95baca
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 23 deletions.
20 changes: 11 additions & 9 deletions src/Share/Postgres/Search/DefinitionSearch/Queries.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module Share.Postgres.Search.DefinitionSearch.Queries
claimUnsyncedRelease,
insertDefinitionDocuments,
cleanIndexForRelease,
defNameSearch,
defNameInfixSearch,
definitionSearch,
DefnNameSearchFilter (..),
-- Exported for logging/debugging
Expand Down Expand Up @@ -266,8 +266,9 @@ data DefnNameSearchFilter
| ReleaseFilter ReleaseId
| UserFilter UserId

defNameSearch :: Maybe UserId -> Maybe DefnNameSearchFilter -> Query -> Limit -> Transaction e [(ProjectId, ReleaseId, Name, TermOrTypeTag)]
defNameSearch mayCaller mayFilter (Query query) limit = do
-- | Find definitions whose name contains the query.
defNameInfixSearch :: Maybe UserId -> Maybe DefnNameSearchFilter -> Query -> Limit -> Transaction e [(ProjectId, ReleaseId, Name, TermOrTypeTag)]
defNameInfixSearch mayCaller mayFilter (Query query) limit = do
let filters = case mayFilter of
Just (ProjectFilter projId) -> [sql| AND doc.project_id = #{projId} |]
Just (ReleaseFilter relId) -> [sql| AND doc.release_id = #{relId} |]
Expand All @@ -280,10 +281,8 @@ defNameSearch mayCaller mayFilter (Query query) limit = do
JOIN projects p ON p.id = doc.project_id
JOIN project_releases r ON r.id = doc.release_id
WHERE
-- Search name by a trigram 'word similarity'
-- which will match if the query is similar to any 'word' (e.g. name segment)
-- in the name.
#{query} <% doc.name
-- Find names which contain the query
doc.name ILIKE ('%' || like_escape(#{query}) || '%')
AND (NOT p.private OR (#{mayCaller} IS NOT NULL AND EXISTS (SELECT FROM accessible_private_projects pp WHERE pp.user_id = #{mayCaller} AND pp.project_id = p.id)))
^{filters}
ORDER BY doc.project_id, doc.name, r.major_version, r.minor_version, r.patch_version
Expand All @@ -292,14 +291,17 @@ defNameSearch mayCaller mayFilter (Query query) limit = do
best_results(project_id, release_id, name, tag) AS (
SELECT m.project_id, m.release_id, m.name, m.tag
FROM matches_deduped_by_project m
ORDER BY similarity(#{query}, m.name) DESC
-- Prefer matches where the query is near the end of the name,
-- e.g. for query 'List', 'data.List' should come before 'data.List.map'
ORDER BY length(m.name) - position(#{query} in m.name) ASC
LIMIT #{limit}
)
-- THEN sort docs to the bottom.
SELECT br.project_id, br.release_id, br.name, br.tag
FROM best_results br
-- docs and tests to the bottom, but otherwise sort by quality of the match.
ORDER BY (br.tag <> 'doc'::definition_tag, br.tag <> 'test'::definition_tag, br.name LIKE ('%' || like_escape(#{query})), similarity(#{query}, br.name)) DESC
ORDER BY br.tag <> 'doc'::definition_tag, br.tag <> 'test'::definition_tag DESC,
length(br.name) - position(#{query} in br.name) ASC
|]

definitionSearch :: Maybe UserId -> Maybe DefnNameSearchFilter -> Limit -> Set (DefnSearchToken (Either Name ShortHash)) -> Maybe Arity -> Transaction e [(ProjectId, ReleaseId, Name, TermOrTypeSummary)]
Expand Down
26 changes: 24 additions & 2 deletions src/Share/Web/Share/Impl.hs
Original file line number Diff line number Diff line change
Expand Up @@ -380,14 +380,36 @@ searchDefinitionNamesEndpoint ::
Maybe IDs.ProjectShortHand ->
Maybe IDs.ReleaseVersion ->
WebApp [DefinitionNameSearchResult]
searchDefinitionNamesEndpoint callerUserId query mayLimit userFilter projectFilter releaseFilter = do
searchDefinitionNamesEndpoint callerUserId query@(Query queryText) mayLimit userFilter projectFilter releaseFilter = do
filter <- runMaybeT $ resolveProjectAndReleaseFilter projectFilter releaseFilter <|> resolveUserFilter userFilter
matches <- PG.runTransaction $ DDQ.defNameSearch callerUserId filter query limit
matches <-
(PG.runTransaction $ DDQ.defNameInfixSearch callerUserId filter query limit)
<&> over (traversed . _3) (rewriteMatches queryText)
let response = matches <&> \(_projId, _releaseId, name, tag) -> DefinitionNameSearchResult name tag
pure response
where
limit = fromMaybe (Limit 20) mayLimit

-- Try to rewrite the name to only include the part of the name that matches the query,
-- and any following suffix.
-- >>> Name.toText $ rewriteMatches "foo" (Name.unsafeParseText "foo.bar.baz")
-- "foo.bar.baz"
--
-- >>> Name.toText $ rewriteMatches "List.ma" (Name.unsafeParseText "data.List.map")
-- "List.map"
--
-- No match; we shouldn't get these back from the query, but if we do, just return the name as is.
-- >>> Name.toText $ rewriteMatches "foo" (Name.unsafeParseText "bar.baz")
-- "bar.baz"
rewriteMatches :: Text -> Name -> Name
rewriteMatches q name
| nameText <- Name.toText name,
Text.isInfixOf q nameText =
let (_before, after) = Text.breakOnEnd q nameText
in Name.parseText (q <> after)
& fromMaybe name
| otherwise = name

resolveProjectAndReleaseFilter :: Maybe IDs.ProjectShortHand -> Maybe IDs.ReleaseVersion -> MaybeT WebApp DDQ.DefnNameSearchFilter
resolveProjectAndReleaseFilter projectFilter releaseFilter = do
projectShortHand <- hoistMaybe projectFilter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
},
"tag": "Plain"
},
"fqn": "List.map",
"fqn": "data.List.map",
"kind": "term",
"projectRef": "@transcripts/search"
}
Expand Down
4 changes: 2 additions & 2 deletions transcripts/share-apis/search/create-release.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"body": {
"causalHashSquashed": "#k64a0e0j4goec5ktrql2q8knot22dakbks05kno7jvr5fha3c894o6hhbkusi7tqegk024d9trmh0v7hikbjn6rrsura5tuecg1bt8o",
"causalHashUnsquashed": "#1d13nals2i51pbupql9vm16qqsvr9svld305f5uijrslk26vuqunq9sd3mqqsn8lsecgocdmn7fr7cujgppsp3lie9j1fc68mfeua28",
"causalHashSquashed": "#kgss2635bbm50dqgut16165dpivfb9tfecrpijpoc018699fti92jf9e8bh9pr3fe18qbnk1h70g9fj1oh6j3ea0gsia3rocee286k0",
"causalHashUnsquashed": "#41ut9c720q056bp558lo9in3jlo3p75f9hrt3b5hv3nqdmtitr79aihkmk4p0vsh2g4o2kdd3nts5gskmpagceti5rbtunilghdgi58",
"createdAt": "<TIMESTAMP>",
"createdBy": "@transcripts",
"projectRef": "@transcripts/search",
Expand Down
13 changes: 13 additions & 0 deletions transcripts/share-apis/search/name-search-infix.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"body": [
{
"tag": "plain",
"token": "List.map"
}
],
"status": [
{
"status_code": 200
}
]
}
6 changes: 1 addition & 5 deletions transcripts/share-apis/search/name-search-suffix.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
"body": [
{
"tag": "plain",
"token": "function.const"
},
{
"tag": "data-constructor",
"token": "data.List.Cons"
"token": "const"
}
],
"status": [
Expand Down
4 changes: 2 additions & 2 deletions transcripts/share-apis/search/prelude.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ function.const a b = a
structural ability Throw e where
throw : e -> a
List.map : (a -> {g} b) -> List a -> {g} List b
List.map f = cases
data.List.map : (a -> {g} b) -> List a -> {g} List b
data.List.map f = cases
(Cons a rest) -> Cons (f a) (List.map f rest)
Nil -> Nil
Expand Down
1 change: 1 addition & 0 deletions transcripts/share-apis/search/run.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ done
# Name searches
fetch "$transcript_user" GET 'name-search-suffix' '/search-names?query=const'
fetch "$transcript_user" GET 'name-search-prefix' '/search-names?query=Func'
fetch "$transcript_user" GET 'name-search-infix' '/search-names?query=List.ma'

# Type searches
# "b -> a -> a"
Expand Down
2 changes: 1 addition & 1 deletion transcripts/share-apis/search/similar-type-search.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
},
"tag": "Plain"
},
"fqn": "List.map",
"fqn": "data.List.map",
"kind": "term",
"projectRef": "@transcripts/search"
}
Expand Down
2 changes: 1 addition & 1 deletion transcripts/share-apis/search/type-var-search.json
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@
},
"tag": "Plain"
},
"fqn": "List.map",
"fqn": "data.List.map",
"kind": "term",
"projectRef": "@transcripts/search"
}
Expand Down

0 comments on commit f95baca

Please sign in to comment.