Skip to content

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 objectName when you want a type of work. "Painting of a boat" works better as query: "boat" with filters.objectName: ["Painting"]. /search/interpret gives that suggestion.
  • Page with page and hasMore. totalResults applies 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: true or queryRewritten.

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".