Semantic search
Requires ext
Semantic search, filter, similarity and explanation require the ext level, which is given to partners and research projects. Apply at api@nasjonalmuseet.no.
Semantic search finds images by meaning, not exact words. "Two horses behind a fence" finds images that show that, even when the words are not in the title.
When to use what?
| You want to … | Use |
|---|---|
| describe a motif in plain words | POST /search/semantic |
| filter on object name, technique, year or the artist's gender, without ranking | POST /search/filter |
| find images that resemble an image | POST /search/similar/{imageId} |
| understand why an image matched | POST /search/explain |
| get a suggested search text and filters from free text (pub) | POST /search/interpret |
| find a word that is in the catalogue | Text search, not semantic search |
How it works
Every image has been given keywords made by a language model (AI), in Norwegian and English. The search compares the search text with them and ranks the images by similarity. In addition, words in the catalogue are searched, and the two lists are merged.
Because the ranking is built on AI-generated keywords, the hits may contain errors. That is why it is not part of the open level.
Step 1: Search with a description
curl -s -X POST "https://api.nasjonalmuseet.no/api/v1/search/semantic" \ -H "X-API-Key: $NM_API_KEY_EXT" -H "Content-Type: application/json" \ -d '{"query": "two horses behind a fence", "lang": "en", "resultsPerPage": 5}'
import os import requests
API = "https://api.nasjonalmuseet.no/api/v1" headers = {"X-API-Key": os.environ["NM_API_KEY_EXT"]}
search = { "query": "boat in a storm", "lang": "en", "resultsPerPage": 5, "filters": {"objectName": ["Painting"]}, } r = requests.post(f"{API}/search/semantic", json=search, headers=headers, timeout=60) r.raise_for_status() for hit in r.json()["data"]: print(round(hit["score"], 3), hit["nmId"], hit["mainTitle"])
const API = "https://api.nasjonalmuseet.no/api/v1"; const headers = { "X-API-Key": process.env.NM_API_KEY_EXT, "Content-Type": "application/json" };
const r = await fetch(${API}/search/semantic, {
method: "POST",
headers,
body: JSON.stringify({ query: "woman by a window", lang: "en", resultsPerPage: 5 }),
});
if (!r.ok) throw new Error(HTTP ${r.status});
for (const hit of (await r.json()).data) console.log(hit.score.toFixed(3), hit.nmId, hit.mainTitle);
lang chooses the language of the search and the response. Without lang, both languages
are searched. Each hit has score and bestMatchImage (the image that matched best).
Step 2: Narrow down with filters
The filters are applied before the ranking: objectName, techniques and materials (the
catalogue's values in Norwegian or English), productionDateFrom/To (years) and
creatorGender (female, male, nonBinary, unknown). Without a search text, sorted by
inventory number:
import os import requests
API = "https://api.nasjonalmuseet.no/api/v1" headers = {"X-API-Key": os.environ["NM_API_KEY_EXT"]}
filters = {"objectName": ["Painting"], "techniques": ["Oil paint"], "productionDateFrom": "1880", "productionDateTo": "1900", "resultsPerPage": 5, "lang": "en"} r = requests.post(f"{API}/search/filter", json=filters, headers=headers, timeout=60) r.raise_for_status() response = r.json() print("Total:", response["totalResults"]) for work in response["data"]: print(work["nmId"], work["mainTitle"], work.get("productionYear"))
Step 3: Find similar images
import os import requests
API = "https://api.nasjonalmuseet.no/api/v1" headers = {"X-API-Key": os.environ["NM_API_KEY_EXT"]}
work = requests.get(f"{API}/objects/NG.M.00939", headers=headers, timeout=30).json() image_id = work["primaryImage"]["imageId"] r = requests.post(f"{API}/search/similar/{image_id}", json={"nmId": "NG.M.00939", "resultsPerPage": 5, "lang": "en"}, headers=headers, timeout=60) r.raise_for_status() for hit in r.json()["data"]: print(hit["nmId"], hit["mainTitle"])
Step 4: Get a suggested search text
/search/interpret suggests how a free text can be split into a search text and filters. It
does not search, and the suggestion is only used if you choose it. This request also works
with pub.
curl -s -X POST "https://api.nasjonalmuseet.no/api/v1/search/interpret" \ -H "X-API-Key: $NM_API_KEY" -H "Content-Type: application/json" \ -d '{"query": "painting of a beautiful sunrise", "lang": "en"}'
Good advice
- Describe the motif with several words. "Boat in a storm" gives better hits than "boat". Filler words such as "a" and "of" do no harm.
- Use
objectNamewhen you want a type of work. "Painting of a boat" works better asquery: "boat"withfilters.objectName: ["Painting"]./search/interpretgives that suggestion. - Page with
pageandhasMore.totalResultsapplies to the page, not the whole collection. - Some searches are blocked or rewritten according to the museum's search rules. The response then has
blocked: trueorqueryRewritten.
Common mistakes
- 403: the key is pub. Semantic search requires ext.
- Few hits with
creatorExact: the name must be exactly as it is in the catalogue, for example "Edvard Munch".