Skip to main content

Using the Search API

How to call and query our Elasticsearch Proxy.

Skyler Young avatar
Written by Skyler Young
Updated over 3 months ago

General information

Endpoint

Base Endpoint:

https://search-api.c211.io/v1/elasticsearch/

Access other standard Elasticsearch endpoints after that path, for example Aliases available to you:

GET https://search-api.c211.io/v1/elasticsearch/_aliases

Or basic search:

POST https://search-api.c211.io/v1/elasticsearch/_search

Often, you will want to search for a resources in a particular language. Indexes are named with [tenant_id]-[resources|taxonomies]_[language code]. In order to target a specific index, follow these steps:

  1. Check the _aliases endpoint for indexes you have access to.

  2. Prepend your Elasticsearch _search endpoint with the index name.

That's it! The resulting URL might look like this:

POST https://search-api.c211.io/v1/elasticsearch/[tenant_id]-resources_en/_search

Required Headers

Authorization: Bearer {your_api_key}
Content-Type: application/json

Example queries

The main value of using the Connect 211 Elasticsearch endpoints is taking advantage of features that we build into the data, if you will. In addition to standardizing resource records, we also enable capabilities like:

  • Search by taxonomy, including rollups and partial matches on codes

  • Search by keyword

  • Filter by area served

  • Filter by distance radius

  • Filter on custom facets in your source data set

The following examples outline common search patterns. Filter patterns can be mixed and matched with Search patterns.

Search By Taxonomy

{
"query": {
"nested": {
"path": "taxonomies",
"query": {
"prefix": {
"taxonomies.code.raw": "TJ-3000"
}
}
}
}
}

Search By Multiple Taxonomies

{
"query": {
"nested": {
"path": "taxonomies",
"query": {
"bool": {
"should": [
{ "prefix": { "taxonomies.code.raw": "TJ-3000" } },
{ "prefix": { "taxonomies.code.raw": "DM-1800" } }
],
"minimum_should_match": 1
}
}
}
}
}

Search By Keyword

{
"query": {
"bool": {
"should": [
{
"multi_match": {
"query": "food pantries",
"type": "best_fields",
"operator": "AND",
"fields": [
"organization.name",
"service.name",
"location.name",
"service.description",
"service.summary"
]
}
},
{
"nested": {
"path": "taxonomies",
"query": {
"multi_match": {
"query": "food pantries",
"type": "best_fields",
"operator": "AND",
"fields": [
"taxonomies.name",
"taxonomies.code"
]
}
}
}
}
],
"minimum_should_match": 1
}
}
}

NOTE: We need a second clause to search taxonomies in the example above, because taxonomies are nested. Keyword search without taxonomies is more simple.

{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "food pantries",
"fields": [
"organization.name",
"service.name",
"location.name",
"service.description",
"service.summary"
],
"operator": "AND",
"analyzer": "standard",
"fuzziness": "AUTO"
}
}
]
}
}
}

Geospatial Filters

Filter by Service Area (Polygon-based)

When filtering by service area, the API uses the geo_shape query to find resources whose service areas intersect with a given geometry:

{
"query": {
"bool": {
"filter": [
{
"geo_shape": {
"service_area": {
"shape": {
"type": "point",
"coordinates": [-122.0194, 47.3417]
},
"relation": "intersects"
}
}
}
]
}
}
}

Filter By Distance Radius (Point-based)

For distance-based filtering, the API uses geo_distance on location.point with miles as the unit:

{
"query": {
"bool": {
"filter": [
{
"bool": {
"should": [
{
"bool": {
"must": [
{
"exists": {
"field": "location.point"
}
},
{
"geo_distance": {
"distance": "10miles",
"location.point": {
"lon": -122.0194,
"lat": 47.3417
}
}
}
]
}
},
{
"bool": {
"must_not": {
"exists": {
"field": "location.point"
}
}
}
}
]
}
}
]
}
}
}

Combined Service Area and Distance Filtering

When both coordinates and distance are provided:

{
"query": {
"bool": {
"filter": [
{
"geo_shape": {
"service_area": {
"shape": {
"type": "point",
"coordinates": [-122.0194, 47.3417]
},
"relation": "intersects"
}
}
},
{
"bool": {
"should": [
{
"bool": {
"must": [
{
"exists": {
"field": "location.point"
}
},
{
"geo_distance": {
"distance": "25miles",
"location.point": {
"lon": -122.0194,
"lat": 47.3417
}
}
}
]
}
},
{
"bool": {
"must_not": {
"exists": {
"field": "location.point"
}
}
}
}
]
}
}
]
}
}
}

Sorting by Distance

When coordinates are provided, results are sorted by proximity in meters:

{
"sort": [
{
"priority": "desc"
},
{
"_geo_distance": {
"location.point": {
"lon": -122.0194,
"lat": 47.3417
},
"order": "asc",
"unit": "m",
"mode": "min"
}
}
]
}

Filter By Custom Facets

Single Facet

{
"query": {
"bool": {
"filter": [
{ "term": { "facets.languages.keyword": "Spanish" } }
]
}
}
}

Multiple Facets (OR)

{
"query": {
"bool": {
"filter": [
{ "terms": { "facets.days_of_the_week.keyword": ["Monday", "Tuesday"] } }
]
}
}
}

Combine Facets (AND)

{
"query": {
"bool": {
"filter": [
{ "term": { "facets.languages.keyword": "Spanish" } },
{ "terms": { "facets.days_of_the_week.keyword": ["Monday", "Tuesday"] } },
{ "term": { "facets.call_centers.keyword": "KC211" } }
]
}
}
}

Pagination

In order to change the number of returned results, or otherwise customize pagination, use the from and size properties in your payload. Modifying our first example would look like this:

{
"from": 0,
"size": 20,
"query": {
"nested": {
"path": "taxonomies",
"query": { "prefix": { "taxonomies.code.raw": "TJ-3000" } }
}
}
}

Please don't return more than 100 documents per page.

Additional Resources From Elasticsearch

Apart from knowing how best to capitalize on the data we supply, usage is standard to Elasticsearch and their docs are the best resource:

Did this answer your question?