This vignette attempts to answer
the question of why you should use the pkgmatch
package, by
describing a couple of example applications.
Anybody wanting an answer to the question, “Is there an R package that does that?” will most commonly use a search engine. Here we’ll consider the following example search:
R package to return web search engine results into R as strings or URLs
Note that there is currently no package which does that, nor is there likely to be, because search results are not generally retrievable via APIs, and in the rare cases in which they are, they are always restricted to authorized access only, and thus require API keys (and commonly also payment).
Given that we expect no direct match, it is then not surprising that
most search engines will then deliver a pile
of links to pages on web scraping, even though that word is
not even part of the search. If you’re lucky, the
searcher
package may appear in the results, although
that package does not actually return search results (for reasons
described above, because of which it merely open links in web
browsers).
There is also an R-specific search engine, “rseek.org”, but even that largely fails to
deliver any
useful results. The first actual package mentioned is the
stringdist
package, which is in no way related to our
query (and even then, the link is to the R-journal article describing
the package, and not the package itself). Finally, GitHub has excellent
search facilities, and yet searching for our string there simply returns
no
results matching entire repositories. Although there are huge
numbers of matches in other aspects, such as code or issues, clicking on
those produces very little or no useful information in attempting to
identify repositories matching the search string.
These search engine results illustrate the general difficulty of searching for particular types of result, in our case R packages. Search engines are inherently broad and generic, and use string comparisons to match outputs to inputs, largely regardless of the type of output. This means that search engines are generally poor tools for identifying specific kinds of objects or results, and generally yield mostly “noise” which must be extensively filtered before the desired kinds of objects can be identified and compared.
In summary:
Many people now use language model interfaces, such as phind or perplexity, for web searching. These use complex language embeddings to match inputs to outputs, and so will generally be more likely to return actual R packages as outputs. Clicking on those links shows both to return actual packages, with most results including general web-scraping packages such as rvest, along with more specific packages such as searcher or googleSearchR.
A notable limitation of language model results is nevertheless that training data are collated regardless of age, and so results may frequently include old or obsolete packages (such as RSelenium or RCrawler). Mis-matches may also occur, such as confusion between google’s “serp-api” for their search engine, and the R package named “serp”, which is completely unrelated. There are also potential ethical ramifications of many language models, notably including that models capable of reproducing code should respect licensing conditions of that code. This may prevent models from identifying packages which were not used within their training data due to licensing restrictions.
In summary:
Compared to the true generality of web search engines or language
model interfaces, pkgmatch
is very restricted in scope, but
it overcomes some of the limitations described above because:
However, like language models, pkgmatch may also return false matches, the computational reasons for which are described in the vignettes, How does pkgmatch work? and Why are the results not what I expect?. We nevertheless hope that these advantages make pkgmatch a uniquely useful tool in searching for R packages.
Now let’s look at how it responds to the same input query used above:
text <- "R package to return web search engine results into R as strings or URLs"
pkgmatch::pkgmatch_similar_pkgs (text, corpus = "cran")
#> [1] "RWsearch" "ore" "sos" "gghilbertstrings"
#> [5] "rjsoncons"
Of those top five matches:
The other two seem unrelated, but:
These results illustrate a contrast between the overly-general results of search engines or language models, and pkgmatch results which are highly specific because they are restricted to R packages only. Although we expected no precise match for reasons described above, pkgmatch nevertheless revealed the presence of two very clearly related packages, ‘RWsearch’ and ‘sos’, neither of which were returned in results from either search engines, or large language models.
pkgmatch can also be used when writing R functions or scripts, to
answer the question of which R packages may already exist which do what
I am trying to code. The easiest way to illustrate this is with a
concrete example, like the following attempt to use the httr2
package to
extract data from a search API:
search_api_results <- function (q) {
url <- "https://mysearchapi.com/search"
q <- httr2::httr_request (url) |>
httr2::req_url_query (q = q)
resp <- httr2::req_perform (url)
check <- httr2::resp_check_status (resp)
body <- httr2::resp_body_json (resp)
httr2::req_body_json (body)
}
We can pass this function definition to the pkgmatch_similar_pkgs()
function, first converting it to a single character string, and also
calling the function with the explicit input_is_code = TRUE
parameter to ensure that our input is interpreted as code and not
text.
s <- paste0 (deparse (search_api_results), collapse = "\\n")
pkgs <- pkgmatch_similar_pkgs (s, corpus = "cran", input_is_code = TRUE)
pkgs
#> [1] "nominatimlite" "wikiTools" "httr2" "searcher"
#> [5] "httptest"
We can then call pkgmatch_browse (pkgs)
to open the CRAN
page for each of those packages in our default browser, and follow links
from there to see whether any of those packages might help develop our
function. We can also search for the closest matching functions
instead of packages, although function matching is restricted to the
rOpenSci corpus only.
#> [1] "crul::curl-options" "rnassqs::nassqs_GET"
#> [3] "webmockr::build_httr2_request" "rtweet::search_tweets"
#> [5] "webmockr::build_httr_request"
Again, web pages for all of those functions can be opened by passing
the fns
result to the
pkgmatch_browse()
function. That will open the
documentation pages on docs.ropensci.org, with all
function documentation entries include a link to the corresponding
source code at the top of the page. This demonstrates how pkgmatch can
be used to identify similar source code to any given code input.
Entire packages can also be used as input to pkgmatch functions. The simplest way to do this is to submit the name of an installed package, like this:
As explained in the How does pkgmatch work? vignette, pkgmatch extracts all code and text from the nominated packages and uses these to generate three sets of embeddings: of all package code, and of all text both with and without text from individual function descriptions. Matches with other packages are based on combinations of matches with these three sets of embeddings, as well as matches based on inverse document frequencies for package text (as also explained in the How does pkgmatch work? vignette). The above call yields this result:
#> $text
#> [1] "factormodel" "crul" "healthequal" "httr2" "crumble"
#>
#> $code
#> [1] "shinyKGode" "igraphinshiny" "crul" "httr2"
#> [5] "sparkavro"
As expected, the crul
package appears in the top results
for matching both text and code (although not in first place, for
reasons described in the
Why are the results not what I expect? vignette). Moreover,
the only two packages matched on both code and text are
crul
itself, and the highly-similar httr2
package.
Finally, the ability to pass entire packages to the
pkgmatch_similar_pkgs()
function reflects the original
motivation for this package, which is to provide a useful tool for rOpenSci’s software peer
review process, through enabling editors to easily assess similarity
of new submissions with all previous rOpenSci packages.