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:
Check the
_aliasesendpoint for indexes you have access to.Prepend your Elasticsearch
_searchendpoint 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:
