How do I use the Elasticsearch Query DSL to query an API using Python?

Question:

I’m trying to query the public Art Institute of Chicago API to only show me results that match certain criteria. For example:

  • classification_title = "painting"
  • colorfulness <= 13
  • material_titles includes "paper (fiber product)"

The API documentation states:

Behind the scenes, our search is powered by Elasticsearch. You can use its Query DSL to interact with our API.

I can’t figure out how to take an Elasticsearch DSL JSON-like object and pass it into the API URL, beyond a single criteria.

Here are some working single-criteria examples specific to this API:

requests.get("https://api.artic.edu/api/v1/artworks/search?q=woodblock[classification_title]").json()
requests.get("https://api.artic.edu/api/v1/artworks/search?q=monet[artist_title]").json()

And here are some of my failed attempts to have return only items that pass 2+ criteria items:

requests.get("https://api.artic.edu/api/v1/artworks/search?q=woodblock[classification_title]monet[artist_title]")
requests.get("https://api.artic.edu/api/v1/artworks/search?q=woodblock[classification_title],monet[artist_title]")
requests.get("https://api.artic.edu/api/v1/artworks/search?q=%2Bclassification_title%3A(woodblock)+%2Bartist_title%3A(monet)")

And lastly some of my failed attempts to return more complex criteria, like range:

requests.get("https://api.artic.edu/api/v1/artworks/search?q={range:lte:10}&query[colorfulness]").json()
requests.get("https://api.artic.edu/api/v1/artworks/search?q=<10&query[colorfulness]").json()
requests.get("https://api.artic.edu/api/v1/artworks/search?q=%2Bdate_display%3A%3C1900").json()

All of these failed attempts return data but not within my passed criteria. For example, woodblock[classification_title]monet[artist_title] should return no results.

How could I query all of these criteria, only returning results (if any) that match all these conditions? The JSON-like Query DSL does not seem compatible with a requests.get.

Asked By: Danny

||

Answers:

Solved. I was lacking knowledge on GET and POST. I can indeed use the JSON-like Query DSL. It just needs to be sent as part of a requests.post instead of a requests.get, like so:

import requests

fields = "id,image_id,title,artist_id,classification_title,colorfulness,material_titles"
url = f"https://api.artic.edu/api/v1/artworks/search?&fields={fields}"

criteria = {
    "query": {
        "bool": {
            "must": [
                {"match": {"classification_title": "painting"}},
                {"range": {"colorfulness": {"lte": 13}}},
                {"match": {"material_titles": "paper (fiber product)"}},
            ],
        }
    }
}


r = requests.post(url, json=criteria)
art = r.json()
print(art)

Notice within the requests.post that the desired criteria query is passed through as a json argument, separate from the url.

Answered By: Danny