Package: bonn
bonn-pyNLP Category-Matching toolsA Rust microservice to match queries on the ONS Website to groupings in the ONS taxonomyGetting startedSet up taxonomy.jsonThis should be adapted from the taxonomy.json.example and placed in the root directory.Download or create embeddingsThese are most simply sourced aspretrained fifu models, but can be dynamically generated
using the embedded FinalFusion libraries.To build wheels for distribution, use:makeConfigurationConfigurationEnvironment variableDefaultDescriptionCATEGORY_API_HOST0.0.0.0HostCATEGORY_API_PORT28800Port that the API is listening onCATEGORY_API_DUMMY_RUNfalseReturns empty list for testing purposesCATEGORY_API_DEBUG_LEVEL_FOR_DYNACONF"DEBUG"Verbosity of dynaconf internal loggingCATEGORY_API_ENVVAR_PREFIX_FOR_DYNACONF"CATEGORY_API"The prefix of which variables to be taken into dynaconf configurationCATEGORY_API_FIFU_FILE"test_data/wiki.en.fifu"The location of the final fusion fileCATEGORY_API_THRESHOLD0.4Threshold of what's considered a low-scoring categoryCATEGORY_API_CACHE_S3_BUCKETS3 for bucket for cache files in format "s3://"--------core variables--------------------------------BONN_CACHE_TARGET"cache.json"Cache targetBONN_ELASTICSEARCH_HOST"http://localhost:9200"Elasticsearch hostBONN_REBUILD_CACHEtrueShould cache be rebuildBONN_TAXONOMY_LOCATION"test_data/taxonomy.json"Location of taxonomyBONN_ELASTICSEARCH_INDEX"ons1639492069322"Location of taxonomyBONN_WEIGHTING__C1Word vectors based on the words in the category nameBONN_WEIGHTING__SC2Word vectors based on the words in the sub-categories nameBONN_WEIGHTING__SSC2Word vectors based on the words in the sub-sub-categories nameBONN_WEIGHTING__WC6Based on a bag of words found in the metadata of the datasets found in the categoriesBONN_WEIGHTING__WSSC8Based on a bag of words found in the metadata of the datasets found in the sub-sub-categoriesManual buildingQuick Local Setupsetup .env file -$ cp .env.local .envmake wheelsmake sure you've placed taxonomy.json in the root folder (This should be obtained from ONS).[TODO: genericize] you need an elasticsearch container forwarded to port:9200 (you can customize the port in .env) with a dump matching the appropriate schemahttps://gitlab.com/flaxandteal/onyx/dp-search-apiin this readme you can checkout how to setup elasticsearch.Install finalfusion utilscdcoreRUSTFLAGS="-C link-args=-lcblas -llapack"cargoinstallfinalfusion-utils--features=opqOptional: Convert the model to quantized fifu formatNote: if you try to use the full wiki bin you'll need about 128GB of RAM...finalfusionquantize-ffasttext-qopq<fasttext.bin>fasttext.fifu.opqInstall deps and buildpoetryshellcdcore
poetryinstallcd../api
poetryinstallexitRunpoetryrunpython-c"from bonn import FfModel; FfModel('test_data/wiki.en.fifu').eval('Hello')"Create cacheYou can create a cache with the following command:poetryrunpython-mbonn.extractThis assumes that the correct environment variables for the NLP model, taxonomy and Elasticsearch are set.AlgorithmThe following requirements were identified:Fast response to live requestsLow running resource requirements, as far as possibleAbility to limit risk of unintended bias in results, and making results explainableMinimal needed preprocessing of data (at least for first version)Non-invasive - ensuring that the system can enhance existing work by ONS teams, with minimal changes required to incorporateRuns effectively and reproducibly in ONS workflowsWe found that the most effective approach was to use the standard Wikipedia unstructured word2vec model as the ML basis.This has an additional advantage that we have been able to prototype incorporating other language category matching into the algorithm, although further work is required, including manual review by native speakers and initial results suggest that a larger language corpus would be required for training.Using finalfusion libraries in Rust enables mmapping for memory efficiency.Category VectorsA bag of words is formed, to make a vector for the category - a weighted average of the terms, according to the attribute contributing it:GroupingScore basisCategory (top-level)Literal words within titleSubcategory (second-level)Literal words within titleSubsubcategory (third-level)Literal words within titleRelated words across whole categoryCommon thematic words across all datasets within the categoryRelated words across subsubcategoryCommon thematic words across all datasets within the subsubcategoryTo build a weighted bag of words, the system finds thematically-distinctive words occurring in dataset titles and descriptions
present in the categories, according to the taxonomy. The "thematic distinctiveness" of words in a dataset description
is defined by exceeding a similarity threshold to terms in the category title.These can then be compared to search queries word-by-word, obtaining a score for each taxonomy entry, for a given phrase.Scoring AdjustmentIn addition to the direct cosine similarity of these vectors, we:remove any stopwords from the search scoring, with certain additional words that should not affect the category matching (“data”, “statistics”, “measure(s)”)apply an overall significance boost for a category, using the magnitude of the average word vector for its bag as a proxy for how “significant” it is that it matches a query phrase (so categories that match overly frequently, such as “population”, are slightly deprioritized)enhance or reduce contribution from each of the words in the query based on their commonality across categories.To do the last, a global count of (lemmatized) words appearing in dataset descriptions/titles across all categories is made, and common terms are deprioritized within the bag according to an exponential decay function - this allows us to rely more heavily on words that strongly signpost a category (such as “education” or “school”) without being confounded by words many categories contain (such as “price” or “economic”).Once per-category scores for a search phrase are obtained, we filter them based on:appearance thresholds, to ensure we only return matches over a minimal viable score;a signal-to-noise ratio filter (SNR) that returns a small number of notably high-scoring categories or a larger group of less distinguishable top scorers, according to a supplied SNR ratio.LicensePrepared by Flax & Teal Limited for ONS Alpha project.
Copyright © 2022, Office for National Statistics (https://www.ons.gov.uk)Released under MIT license, seeLICENSEfor details.