{"id":43223285,"url":"https://github.com/gnames/gnmatcher","last_synced_at":"2026-02-01T09:15:54.604Z","repository":{"id":89726287,"uuid":"216730496","full_name":"gnames/gnmatcher","owner":"gnames","description":"gnmatcher provides fast stemming, fuzzy matching altorithms for matching scientific names","archived":false,"fork":false,"pushed_at":"2025-09-30T16:40:43.000Z","size":2464,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-09-30T18:28:30.259Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gnames.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-10-22T05:32:12.000Z","updated_at":"2025-09-30T16:40:43.000Z","dependencies_parsed_at":"2024-11-04T12:20:11.390Z","dependency_job_id":"3bcf1abe-db39-491c-84d7-a3f785d4613f","html_url":"https://github.com/gnames/gnmatcher","commit_stats":null,"previous_names":[],"tags_count":76,"template":false,"template_full_name":null,"purl":"pkg:github/gnames/gnmatcher","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnames%2Fgnmatcher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnames%2Fgnmatcher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnames%2Fgnmatcher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnames%2Fgnmatcher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gnames","download_url":"https://codeload.github.com/gnames/gnmatcher/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnames%2Fgnmatcher/sbom","scorecard":{"id":431023,"data":{"date":"2025-08-11","repo":{"name":"github.com/gnames/gnmatcher","commit":"c81c431a36ce288c1e762e36ad56ba8010bfaefa"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.4,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: Dockerfile:1: pin your Docker image by updating alpine:3.17 to alpine:3.17@sha256:8fc3dacfb6d69da8d44e42390de777e48577085db99aa4e4af35f483eb08b989","Info:   0 out of   1 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v1.1.9 not signed: https://api.github.com/repos/gnames/gnmatcher/releases/127935892","Warn: release artifact v1.1.4 not signed: https://api.github.com/repos/gnames/gnmatcher/releases/109236000","Warn: release artifact v1.0.1 not signed: https://api.github.com/repos/gnames/gnmatcher/releases/78747737","Warn: release artifact v1.0.0-RC1 not signed: https://api.github.com/repos/gnames/gnmatcher/releases/66523632","Warn: release artifact v0.9.9 not signed: https://api.github.com/repos/gnames/gnmatcher/releases/66118257","Warn: release artifact v1.1.9 does not have provenance: https://api.github.com/repos/gnames/gnmatcher/releases/127935892","Warn: release artifact v1.1.4 does not have provenance: https://api.github.com/repos/gnames/gnmatcher/releases/109236000","Warn: release artifact v1.0.1 does not have provenance: https://api.github.com/repos/gnames/gnmatcher/releases/78747737","Warn: release artifact v1.0.0-RC1 does not have provenance: https://api.github.com/repos/gnames/gnmatcher/releases/66523632","Warn: release artifact v0.9.9 does not have provenance: https://api.github.com/repos/gnames/gnmatcher/releases/66118257"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2025-3787 / GHSA-fv92-fjc5-jj9h"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T03:21:14.965Z","repository_id":89726287,"created_at":"2025-08-19T03:21:14.965Z","updated_at":"2025-08-19T03:21:14.965Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28974537,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T08:16:14.655Z","status":"ssl_error","status_checked_at":"2026-02-01T08:06:51.373Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-01T09:15:54.106Z","updated_at":"2026-02-01T09:15:54.598Z","avatar_url":"https://github.com/gnames.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gnmatcher\n\n[![API](https://img.shields.io/badge/OpenAPI3-1.0.0-89bf04)](https://apidoc.globalnames.org/gnmatcher)\n[![GoDoc](https://godoc.org/github.com/gnames/gnmatcher?status.svg)](https://pkg.go.dev/github.com/gnames/gnmatcher)\n\n``import \"github.com/gnames/gnmatcher\"``\n\nThe [GNmatcher] is a utility for checking scientific name-strings against\n[canonical names] derived from a variety of [biodiversity datasets].\nThe matching can be exact, partial, or fuzzy. Usually [GNmatcher] is used\nas a component of a scientific names verification service ([GNames API]).\n\n## Introduction\n\nThe [GNmatcher] takes an array of strings and returns back zero or more\n[canonical names] for each string. If it is not important which biodiversity\nrepositories provided matched [canonical names], the project can be used as\na stand-alone [RESTful service][RESTful API documentation]. If such information is\nimportant, the project is used as a component of a scientific names\nverification  service ([GNames API]).\n\nThe project aims to do canonical names matching as fast and accurate as\npossible. Quite often, humans or character-recognition software (OCR) introduce\nmisspellings in the strings. For this reason, [GNmatcher] uses fuzzy-matching\nalgorithms when no exact match exists.  Also, for cases where full string does\nnot have a match, `gnmatcher` tries to match it against parts of the string.\nFor example, if a string did not get a match on a subspecies level, the\nalgorithm will try to match it on species and genus levels.\n\n*Reconciliation* is the normalization of lexical variants of the same name.\n*Resolution* is a determination of how a nomenclaturally registered name can be\ninterpreted from the point of taxonomy. For example, a name can be an accepted\nname for species, a synonym, or a discarded one.\n\nThe `gnmatcher` app functions as an HTTP service. A client access it wia\nHTTP protocol.  The API's methods and structures are described in\nby the [RESTful API documentation].\n\n## Input and Output\n\nA user calls HTTP resource `/match` sending an array of strings to the service\nand gets back matched canonical names, the match type, as well as other\nmetadata described as a `Match` object in the [RESTful API documentation].\n\nThe optimal size of the input is 5-10 thousand strings per array. Note\nthat 10,000 is the maximal size, and larger arrays will be truncated.\n\nIf the service is used with 'relaxed fuzzy matching' option, only 50 strings\ncan be processed at a time.\n\n## Performance\n\nFor performance measurement we took [100,000 strings][testdata] where only\n30% of them were 'real' names. On a modern CPU with 12 hyper threads and\n`GNM_JOBS_NUM` environment variable set to 8, the service was able to process\nabout 8,000 strings per second. For 'clean' data where most of the names\nare \"real\", you should see an even higher performance.\n\n## Prerequisites\n\n* You will need PostgreSQL with a restored dump of\n   [`gnames` database][gnames dump].\n* For PostgreSQL collation to work correctly set ``LC_COLLATE=C`` in\n  `/etc/default/locale`\n* Docker service\n\n## Usage\n\n### Usage with docker\n\n* Install docker `gnmatcher` image: ``docker pull gnames/gnmatcher``.\n\n* Copy [.env.example] file on user's disk and change values\n  of environment variables accordingly.\n\n* Start the service:\n\n    ```bash\n    docker run -p 8080:8080 -d --env-file your-env-file \\\n    gnames/gnmatcher -- rest -p 8080`\n    ```\n\n  This command will set the service on port 8080 and will make it available\n  through port 8080 on a local machine.\n\n### Usage from command line\n\n* Download the [latest verion] of `gnmatcher` binary, untar and put somewhere\n  in `PATH`.\n\n* Run `gnmatcher -V` to generate configuration at\n  `~/.config/gnmatcher.yaml`\n\n* Edit `~/.config/gnmatcher.yaml` accordingly.\n\n* Run ``gnmatcher rest -p 1234``\n\nThe service will run on the given port (the default port is 8080).\n\n### Usage as a library\n\n```go\npackage main\n\nimport (\n  \"fmt\"\n  gnmatcher \"github.com/gnames/gnmatcher/pkg\"\n  \"github.com/gnames/gnmatcher/pkg/config\"\n  \"github.com/gnames/gnmatcher/internal/io/bloom\"\n  \"github.com/gnames/gnmatcher/internal/io/trie\"\n  \"github.com/gnames/gnmatcher/internal/io/virusio\"\n)\n\nfunc Example() {\n\t// Note that it takes several minutes to initialize lookup data structures.\n\t// Requirement for initialization: Postgresql database with loaded\n\t// http://opendata.globalnames.org/dumps/gnames-latest.sql.gz\n\t//\n\t// If data are imported already, it still takes several seconds to\n\t// load lookup data into memory.\n\tcfg := config.New()\n\tem := bloom.New(cfg)\n\tfm := trie.New(cfg)\n\tvm := virusio.New(cfg)\n\tgnm := gnmatcher.New(em, fm, vm, cfg)\n\tres := gnm.MatchNames([]string{\"Pomatomus saltator\", \"Pardosa moesta\"})\n\tfor _, match := range res.Matches {\n\t\tfmt.Println(match.Name)\n\t\tfmt.Println(match.MatchType)\n\t\tfor _, item := range match.MatchItems {\n\t\t\tfmt.Println(item.MatchStr)\n\t\t\tfmt.Println(item.EditDistance)\n\t\t}\n\t}\n}\n```\n\n## Configuration\n\nYou can use either cofiguration file, or environment variables.\nConfiguration file is usually located at `$HOME/.config/gnmatcher.yaml`.\nWhen `gnmatcher` runs first time, it will create the configuration file.\nLogs provide the location of the configuration file with every run of\n`gnmatcher`. The meanings of configuration options are documented in\nthe config file.\n\nTo make it easier to run gnmatcher in a container, or a Kubernetes pod, there\nare also environment variables that override configuration file values.\n\n| Env. Var.                | Configuration      |\n| ------------------------ | ------------------ |\n| GNM_CACHE_DIR            | CacheDir           |\n| GNM_JOBS_NUM             | JobsNum            |\n| GNM_PG_HOST              | PgHost             |\n| GNM_PG_PORT              | PgPort             |\n| GNM_PG_USER              | PgUser             |\n| GNM_PG_PASS              | PgPass             |\n| GNM_PG_DB                | PgDB               |\n\n## Client\n\nA user can find an example of a client for the service in this\n[test file][rest-client].\n\nThe API is formally described in the [RESTful API documentation]\n\n## Development\n\nThere is a docker-compose file that sets up HTTP service to run tests. To run\nit to the following:\n\n1. Copy `.env.example` file to the `.env` file in the project's root directory,\n   change the settings accordingly.\n\n2. Build the `gnmatcher` binary and docker image using ``make dc`` command.\n\n3. Run docker-compose command ``docker compose up``\n\n4. Run tests via ``go test ./... -v``\n\n[.env.example]: https://raw.githubusercontent.com/gnames/gnmatcher/master/.env.example\n[BDD]: https://en.wikipedia.org/wiki/Behavior-driven_development\n[RESTful API documentation]: https://apidoc.globalnames.org/gnmatcher\n[biodiversity datasets]: https://verifier.globalnames.org/data_sources\n[canonical names]: https://globalnames.org/docs/glossary/#canonical-name\n[gnames dump]: https://opendata.globalnames.org/dumps/gnames-latest.sql.gz\n[gnames]: https://github.com/gnames/gnames\n[gnmatcher interface]: https://pkg.go.dev/github.com/gnames/gnmatcher#GNmatcher\n[model]: https://github.com/gnames/gnmatcher/tree/master/model\n[rest-client]: https://github.com/gnames/gnmatcher/blob/master/rest/rest_test.go\n[testdata]: https://github.com/gnames/gnmatcher/blob/master/testdata/testdata.csv\n[GNmatcher]: https://github.com/gnames/gnmatcher\n[GNames]: https://github.com/gnames/gnames\n[GNames API]: https://apidoc.globalnames.org/gnames\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnames%2Fgnmatcher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgnames%2Fgnmatcher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnames%2Fgnmatcher/lists"}