Skip to content

How to work with the Search service

Search service as part of the Infocenter is designed to speed up database searches. We are using Azure Cognitive Search

https://api.discover.swiss/info/v1/search

There are GET and POST endpoints for search.

Search request

Parameter Type Description
searchText string Optional. Search for contained string by the searchable fields
searchFields string Optional. When name of fields are specified as a comma separated string (e.g. "name, description, address/name") then only the selected fields will be used for searching.
select string Optional. When name of fields are specified as a comma separated string (e.g. "name, description, @id, address") then only the selected fields will be returned.
filters string[] Optional. Odata strings for filters
currentPage int Optional. By default equal 1. Determines how many results are in response
resultsPerPage int Optional. By default equal 10. Determines how many results are in response
orderBy string Optional. Determines name of field by which result will be ordered
facets FacetRequest[] List of facets which will be iin the response

Custom filter properies

Parameter Type Description
datasource string[] Optional. Determines one or many datasource by which data will be filtered
project string[] Optional. Determines one or many datasource by which data will be filtered
campaignTag string[] Optional. Determines one or many campaign tag by which data will be filtered

Facets filter properies

For filtering by facets is necessary to use porerty filterPropertyName from Search facet response as a request property name. These properties are optional and have string[] type.

List of available facets filters
facet name filter property name description
address/addressLocality addressLocality
address/postalCode addressPostalCode
tag/id tag
categoryTree category represent category tree list. For getting full list of categories don't forget to set big enough value for count property in facet request
containedInPlace/id containedInPlace
time time
state state
rating/condition ratingСondition
rating/difficulty ratingDifficulty
elevation/ascent elevationAscent
elevation/descent elevationDescent
elevation/minAltitude elevationMinAltitude
elevation/maxAltitude elevationMaxAltitude
seasons season
type type
parentType parentType By filtering with the parentType you get all objects of the type and all derived types. For example: 'LocalBusiness' -> LocalBusiness, FoodEstablishment, LodgingBusiness

Localization

default: de-CH

Language: Based on the Accept-Language header localized properties are translated. Search language is based on this header as well (e.g. for de-CH it will search only in german translations if the translation is available for this porperty.

Search response

Any search response contains list of possible filters and total number of results matching current query.

Property name Type Description
count int (nullable) actual count of results in actual query but not count possible results
values SearchValueResponse[] paged count of results by query
facets {string, SearchFacetResponse}[] Dictionary of facets by the query. Where the key is a string with name of facets from azure search, and the value is SearchFacetResponse

Searching

Properties names should be in CamelCase.

Warning

When you are searching in specific language don't forget to setup necessary language in Accept-Language header, otherwise you can receive an incorrect response.

Search samples

Search with pagination and ordering by property name

https://api.discover.swiss/info/v1/search?OrderBy=additionalType&ResultsPerPage=5&CurrentPage=1
https://api.discover.swiss/info/v1/search?SearchText=Scuol, Gurl* +"Tarasp fontana" -spaceship

The query parser separates operators (such as *, + and - in the example) from search terms, and deconstructs the search query into subqueries of a supported type:

  • term query for standalone terms (like Scuol)
  • phrase query for quoted terms (like Tarasp fontana or)
  • prefix query for terms followed by a prefix operator * (like Gurl)

Search by selected language

To search by language it is necessary language it is neccessary to specify Accept-Language header, and set SearchText.

HEADERS: Accept-Language: "en"

https://api.discover.swiss/info/v1/search?search?SearchText=Switzerland&Type=AdministrativeArea

Search by selected fields

There is a possibility to specify SearchFields if you want to search by specific field.

Information

Search is using all searchable fields when SearchFields is empty.

There are available searchable fields:

Field name Translated
openingHours -
address/name +
address/addressLine -
address/streetAddress -
description +
name +

Translated field means that this property is available in different languages.

For declaring multiple fields in SearchFields property they should be separated by comma:

-SearchFields=name, description -SearchFields=name, address/name, description -SearchFields=address/name

Sample of searching by single fields
https://api.discover.swiss/info/v1/search?search?SearchText=Schweiz&SearchFields=name&Type=AdministrativeArea
Sample of searching by multiple fields
https://api.discover.swiss/info/v1/search?search?SearchText=Schweiz&SearchFields=name, address/name

Facets

There are next facets in the response:

facet name filter property name description
address/addressLocality addressLocality
address/postalCode addressPostalCode
tag/id tag
categoryTree category represent category tree list. For getting full list of categories don't forget to set big enough value for count property in facet request
containedInPlace/id containedInPlace
time time
state state
rating/condition ratingСondition
rating/difficulty ratingDifficulty
elevation/ascent elevationAscent
elevation/descent elevationDescent
elevation/minAltitude elevationMinAltitude
elevation/maxAltitude elevationMaxAltitude
seasons season
type type
parentType parentType By filtering with the parentType you get all objects of the type and all derived types. For example: 'LocalBusiness' -> LocalBusiness, FoodEstablishment, LodgingBusiness

see search facet response

see search facet value response

Attention

It is important to use single quotes with 'string' value type and don't use single quotes with 'int' value type

Warning

For getting full list of categories don't forget to set big enough value for count property in facet request

Control of facets through facet request

You use POST requests to get more control under the facets reposnes.

In post request body you can pass array of facets request.

Search facet request

Parameter Type Description
name string name of facet that will be in the response
values string property that represent borders for range response
interval int property that represent interval borders for range response
count int count of facets in the reponse

there is different responses based on request:

Search Request Body Request type Desscription
{ "facets": null } or { //don't set any facets } POST, GET Returns all facets
{ "facets": [] } POST With empty array it doesn’t return any facets
{ "facets": [{ "name": "category" }]} POST Returns only categoryTree facets

Usage of range and interval in facets

You can get facets grouped by the range of numbers.

For example range of rating conditions:

{
  "rating/condition": {
    "filterPropertyName": "ratingCondition",
    "values": [{...},
      {
        "facetType": "range",
        "filterType": "object",
        "valueType": "int",
        "from": 10,
        "to": 25,
        "count": 15,
        "value": null,
        "name": "10 - 25",
        "query": "query:rating/condition gt 10 and rating/condition le 25"
      },{...}]
  }
}

Warning

Range facets appliable only for facets with int type.

You can get range facets by 2 ways:

  • use values
  • use interval
Get ranges through values

Property values is a string which should be represented in the next format: number|number

Facet values property has next restrictions:

  • values and interval cannot exist in the same time
  • values could contain only int and should be delimited by |, e.g. 10|15|3 - valid, |5|10 - invalid

Here is example how it could be:

// POST search request body
{
  "facets": {
    "name": "ratingCondition",
    "values": "5|15|34"
  }
}
// alternative
{
  "facets": {
    "name": "rating/condition",
    "values": "10|25|34"
  }
} ```

Response for that request will have the next structure:

``` json
{
  "rating/condition": {
    "filterPropertyName": "ratingCondition",
    "values": [{...},{
    "facetType": "range",
    "filterType": "object",
    "valueType": "int",
    "from": 10,
    "to": 25,
    "count": 15,
    "value": null,
    "name": "10 - 25",
    "query": "query:rating/condition gt 10 and rating/condition le 25"
    },{...}]
  }
}
Get ranges through interval

Property interval should be a number

Facet inreval property has next restrictions:

  • values and interval cannot exist in the same time
  • interval should be integer
  • interval should be greater than or equal to 0

Here is example how it could be:

// POST search request body
{
  "facets": {
    "name": "ratingCondition",
    "interval": "2"
  }
}
// alternative
{
  "facets": {
    "name": "rating/condition",
    "values": "2"
  }
}

Response for that request will have the next structure:

{
  "rating/condition": {
    "filterPropertyName": "ratingCondition",
    "values": [{...},{
    "facetType": "range",
    "filterType": "object",
    "valueType": "int",
    "from": 2,
    "to": 4,
    "count": 15,
    "value": null,
    "name": "2 - 4",
    "query": "query:rating/condition gt 2 and rating/condition le 4"
    },{...}]
  }
}

Filtering by the facet

Filtering by facets is easy with usage of filterPropertyName property from search facet value response and query property from search facet value response.

// sample facet response
{
  "filterPropertyName": "ratingCondition",
  "values": [
    {
      ... // other facet value response properties
      query = "2"
    },
    {
      ... // other facet value response properties
      query = "9"
    }
}

It is how we can use that as filters in get request:

https://api.discover.swiss/info/v1/search?ratingCondition=5&ratingCondition=9

It is how we can use that as filters in post request:

// request body with filter by single query:
{
  "ratingCondition":"5"
}
// or
{
  "ratingCondition": ["5"]
}

// and this is body for filtering by multiple query of one property:
{
  "ratingCondition":["5", "9"]
}

Facet response

// search response
{
  count: 15,
  values: [{...},{...}]
  facets:{
    "categoryTree": {
      filterPropertyName: "category",
      values: [
        {
          ...
          "query": "query:item eq 'SomeCategory'"
        }, {...}
      ]
    },  
    "rating/condition" : {
      filterPropertyName: "ratingCondition",
      values: [
        {
          ...
          "query": "2"
        },
        {
          ...
          "query": "6"
        }
      ]
    }
  }
}

Request body based on facet

// search request by category and rating/conditions query
{
  "category": "query:item eq 'SomeCategory'",
  "ratingCondition": "2"
}
// search request by category and multiple rating/conditions query
{
  "category": "query:item eq 'SomeCategory'",
  "ratingCondition": ["2", "6"]
}

Sample of filtering by the facet with 'int' valueType

Get request:

https://api.discover.swiss/info/v1/search?filters=time eq 50

Post request:

{
  "filters": "time eq 50"
}

Sample of filtering by the facet with 'string' valueType

Get request:

https://api.discover.swiss/info/v1/search?filters=address/addressLocality eq 'Martina'

Post request:

{
  "filters": "address/addressLocality eq 'Martina'"
}

Filtering

A filter provides criteria for selecting entries used in an query. Unfiltered search includes all entries in the index. A filter scopes a search query to a subset of documents.

It is possible to use filtering by multiple ways:

  • use OData for filtering by every filterable property. See filterable properties in search index schema.
    Complex to use but gives you full control.
  • use custom filter properties for filtering. See request strucuture here
    Simplified usage without Azure Search internal know-how.
  • use facets filter properies. For filtering by facets is necessary to use porerty filterPropertyName from Search facet response as a request property name. See Facets. Simplified usage without Azure Search internal know-how.

Filtering samples

Filtering by category with odata filters

https://api.discover.swiss/info/v1/search?ResultsPerPage=5&CurrentPage=1&Filters=categoryTree/any(category: category eq 'TSVM-OUA_3642936')

Filtering by Category(-ies) (request parameter)

Get request:

https://api.discover.swiss/info/v1/search?Category=ZHT-CMS_place|ZHT-CMS_shopping&Category=ZHT-CMS_place|ZHT-CMS_sport

Post request:

{
  "category": ["ZHT-CMS_place|ZHT-CMS_shopping","ZHT-CMS_place|ZHT-CMS_sport"]
}

Filtering by Datasource (request parameter) and by identifier (odata filters)

Get request:

https://api.discover.swiss/info/v1/search?filters=identifier eq 'TSVM-OUA_9702544'&Datasource=TSVM-OUA

Post request:

{
  "filters": "identifier eq 'TSVM-OUA_9702544'",
  "datasource":"TSVM-OUA"
}

Filtering by Types and Datasources

Get request:

https://api.discover.swiss/info/v1/search?Type=Tour&Type=Place&Datasource=ZHT-CMS&Datasource=TSVM-OUA

Post request:

{
  "type":["Place", "Tour"],
  "datasource": ["TSVM-OUA", "ZHT-CMS"]
}

Filtering by ParentTypes

Get request:

https://api.discover.swiss/info/v1/search?parentType=Place

Post request:

{
  "parentType":["Place"]
}

Filtering by the time range

Get request:

https://api.discover.swiss/info/v1/search?Type=Tour&filters=((time gt 50) and (time lt 60)) or ((time gt 100) and (time lt 150))

Post request:

{
  "type":"Tour",
  "filters": "((time gt 50) and (time lt 60)) or ((time gt 100) and (time lt 150))"
}

Filtering by geo with odatafilters

Search Api supports geo-spatial queries in OData filter expressions via the geo.distance and geo.intersects functions. The geo.distance function returns the distance in kilometers between two points, one being a field or range variable, and one being a constant passed as part of the filter. The geo.intersects function returns true if a given point is within a given polygon, where the point is a field or range variable and the polygon is specified as a constant passed as part of the filter.

Filtreing by distance

The geo.distance function takes two parameters of type Edm.GeographyPoint and returns an Edm.Double value that is the distance between them in kilometers. This differs from other services that support OData geo-spatial operations, which typically return distances in meters.

One of the parameters to geo.distance must be a geography point constant, and the other must be a field path (or a range variable in the case of a filter iterating over a field of type Collection(Edm.GeographyPoint)). The order of these parameters doesn't matter.

The geography point constant is of the form geography'POINT(longitude latitude)', where the longitude and latitude are numeric constants.

Warning

When using geo.distance in a filter, you must compare the distance returned by the function with a constant using lt (lower than), le (lower or equal), gt (greater than), or ge (greater or equal). The operators eq and ne are not supported when comparing distances.

https://api.discover.swiss/info/v2/search?Type=Event&filters=geo.distance(geo, geography'POINT(9.7760155 46.6233053)') ge 5
Filtering by polygons

The geo.intersects function takes a variable of type Edm.GeographyPoint and a constant Edm.GeographyPolygon and returns an Edm.Boolean -- true if the point is within the bounds of the polygon, false otherwise.

Warning

Note that the polygon is closed (the first and last point sets must be the same)

https://api.discover.swiss/info/v2/search?Type=Event&filters=geo.intersects(geo, geography'POLYGON((9.7714376 46.6257781, 9.7614813 46.6244521, 9.7601938 46.6195606, 9.7598076 46.6149633, 9.7702360 46.6131950, 9.7800207 46.6132540, 9.7870588 46.6137550, 9.7913504 46.6189123, 9.7917795 46.6223305, 9.7904062 46.6254539, 9.7860289 46.6272218, 9.7823381 46.6279290, 9.7769308 46.6275754, 9.7736263 46.6261022, 9.7714376 46.6257781))')

Filtering by schedule

Filtering by schedule available only by filters property.

Filteting by schedule/byDay
https://api.discover.swiss/info/v1/search?Type=Event&filters=schedule/any(item: item/byDay/any(day: day eq 'Monday'))

Post request:

{
  "type": "Event",
  "filters": "schedule/any(item: item/byDay/any(day: day eq 'Monday'))"
}
Filtering by schedule/startDate and schedule/endDate

Properties schedule/startDate and schedule/endDate has DateTimeOffset type and value for filtering should be presented in the next format: yyyy-MM-ddTHH:mm:ssZ

Get request:

https://api.discover.swiss/info/v1/search?Type=Event&filters=schedule/any(item: item/startDate lt 2020-04-14T00:00:00Z)
https://api.discover.swiss/info/v1/search?Type=Event&filters=schedule/any(item: item/endDate ge 2020-04-14T00:00:00Z)

Post request:

{
  "type": "Event",
  "filters": "schedule/any(item: item/startDate lt 2020-01-01T00:00:00Z and item/endDate ge 2020-04-01T00:00:00Z)"
}
Filtering by schedule/startTime and schedule/endTime

Azure Search doesn't support TimeSpan and that is why it is presented as string. That is why filtering available only as for strings.

Get request:

https://api.discover.swiss/info/v1/search?Type=Event&filters=schedule/any(item: item/startTime eq '12:00:00')
https://api.discover.swiss/info/v1/search?Type=Event&filters=schedule/any(item: item/endTime eq '12:00:00')

Post request:

{
  "type": "Event",
  "filters": "schedule/any(item: item/startTime eq '12:00:00')"
}

OData filtering

Read more about OData specification you can here

Structure samples

OData filter structure for property

identifier eq 'TSVM-OUA_9702544'

OData filter structure for sub-property

address/addressLocality eq 'Martina'

OData filter structure for array

results/any(item: item eq 'something')

OData filter structure for sub-property in array

categoryTree/any(category: category eq 'ZHT-CMS_restaurants' or category eq 'TSVM-OUA_14359510')

Category tree

You can build a tree from Categories provided in the facets. Property 'value' of each category contains full parent list separated by '|' from root to current category.

Category example:

{
  "value": "ZHT-CMS_gastronomy|ZHT-CMS_restaurants|ZHT-CMS_cuisine",
  "name": "Cuisine"
}

Selecting of fields for result

It is possible to specify which fields should be returned in the response. For that necessary to specify Select parameter with string of fields separated by comma. All fields you see in response (results) are available for selecting.

For returning some nested fields of some other field it is possible to declare nesting by / symbol. In case when field and his nested fields are selected in one query, only root field will have affect.

Examples:

-Select=image/dataGovernance/source/link,image/dataGovernance - in that case image/dataGovernance/source/link will be ignored -Select=image/dataGovernance

Information

Max depth of getting nested fields is 7. (e.g. for root/nested1/nested2/nested3/nested4/nested5/nested6/nested7/nested8 query nested7 and following will be ignored)

Selecting several root fields

Request:

https://api.discover.swiss/info/v1/search?Type=Tour&Select=@id, image, dataGovernance

Response:

"values": [
        {
            "@id": "https://api.discover.swiss/info/v1/tours/TOUR_ID",
            "dataGovernance": {
                "supplier": {
                    "acronym": "ACRONYM"
                },
                "source": {
                    "name": "Name",
                    "logo": {
                        "contentUrl": "link"
                    },
                    "link": [
                        {
                            "url": "link",
                            "type": "type"
                        }
                    ]
                },
                "author": "author"
            },
            "image": {
                "caption": "caption",
                "dataGovernance": {
                    "supplier": {
                        "acronym": "ACRONYM"
                    },
                    "source": {
                        "link": [
                            {
                                "type": "type"
                            }
                        ]
                    }
                },
                "contentUrl": "contentUrl",
                "thumbnailUrl": "thumbnailUrl",
                "@id": "https://api.discover.swiss/info/v1/imageObjects/IMAGE_ID",
                "identifier": "IMAGE_ID"
            }
        },
        {
          ...
        }
]

Selecting root and nested fields

Request:

https://api.discover.swiss/info/v1/search?Type=Tour&Select=dataGovernance/source, dataGovernance/source/name

The response will return all properties under dataGovernance/source because it counts as root property and the more specific property dataGovernance/source/name is included in it:

"values": [
        {
            "dataGovernance": {
                "source": {
                    "name": "name",
                    "logo": {
                        "contentUrl": "contentUrl"
                    },
                    "link": [
                        {
                            "url": "url",
                            "type": "type"
                        }
                    ]
                }
            }
        },
        {
          ...
        }
]

Sample application

You can see search in sample application here: demo.discover.swiss/search


Last update: October 15, 2020 15:50:25