Search code examples
pythonelasticsearchelasticsearch-dsl

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


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.


Solution

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