On this page we'll cover how to search with the IOTICS API's Search Service.

Using the Search Service allows you to run a synchronous GLOBAL or LOCAL search with each available result returned as a chunk. The last chunk will always be a timeout error.

Any user of IOTICS can run a semantic search to find metadata and data feeds both inside their own IOTICSpace and outside, in the IOTICS ecosystem. The search will find and return all Digital Twins matching the set criteria that the user has permission to access.

You can search loosely, such as for text or location, or more specific, such as by specifying exact semantic triple matches.

Once you've found a Twin that matches your criteria you can use the Twin Service to Describe it, see our Twin guide for more information.

On this page we will cover how to:

You can see the entire IOTICS API Reference here.

Set your headers

The headers are an important part of your API request, representing the meta-data of your request. Before submitting a request you need to ensure you have set your headers:

Header

Type

Description

Mandatory

Iotics-ClientRef

String

Any responses associated with the request will include this reference

Optional

Iotics-ClientAppId

String

User namespace used to group all the requests/responses

Mandatory

Iotics-TransactionRef

String

Used to loosely link requests/responses in a distributed environment each layer can add its own id to the list

Limited to:

  • max 16 elements per list
  • max 36 characters

Optional

Iotics-RequestTimeout

String (Date-Time)

Used to stop request processing once timeout value is reached

Mandatory

The request

To search, you just submit a search POST to the IOTICS API's Search service.

You can see an example request here.

Query parameters

You first set the parameters of your query, deciding the scope of your search and how many results to return:

Parameter

Type

Description

lang

String

Language code for properties

scope

String

Choose from:

  • GLOBAL
  • LOCAL
  • LOCAL_OWN
  • AUTO

limit

Int64

Limits amount of results returned.

Default = 500
Maximum = 1000

offset

Int64

Sets where the results are returned from, used with limit to control what is returned

Body parameters

You then set the payload for your request, made up of:

Parameter

Type

Description

expiryTimeout

String (Date-Time)

UTC time for when the search request will expire

filter

Object

Used to filter your results

filter:location

Object

Use to filter by location

filter:location:location

Object

The location being filtered by

filter:location:location:lat

Double

The latitude of the location being filtered by

filter:location:location:lon

Double

The longitude of the location being filtered by

filter:location:location:radiusKm

Double

The radius in km around the location to be filtered by

filter:properties

Array of objects

Used to filter Twin properties

filter:properties:key

String

Filter with the key (predicate) of the properties

filter:properties:key:langLiteralValue

Object

Use a langLiteralValue to filter for a property

filter:properties:key:langLiteralValue:lang

String

The 2- character language code for the property

filter:properties:key:langLiteralValue:value

String

The value of the property you're filtering by

filter:properties:key:literalValue

Object

Use a literalValue to filter by a property

filter:properties:key:literalValue:dataType

String

XSD data type.
Currently supports:
dateTime, time, date, boolean, integer, nonPositiveInteger, negativeInteger, nonNegativeInteger, positiveInteger,
long, unsignedLong, int, unsignedInt, short, unsignedShort, byte, unsignedByte, anyURI

filter:properties:key:literalValue:value

String

String representation of the value according to XSD datatype specification

filter:properties:key:stringLiteralValue

Object

Use a stringLiteralValue to filter by a property

filter:properties:key:stringLiteralValue:value

String

The value of the property you're filtering by

filter:properties:key:uriValue

Object

Use a URI to filter by a property

filter:properties:key:uriValue:value

String

The value of the property you're filtering by

filter:text

String

One or more keywords which must match text from entity

Note: Any, rather than all, of the keywords will produce a match

responseType

String

Choose from:

  • FULL
  • LOCATED
  • MINIMAL

Examples

Example Search Request

This is an example of a request to search for looking for all Weather related Twins within 3km of central Cambridge.

You can build your own example by going to the Search Service reference page.

# REQUIREMENTS:
# Create a python venv and activate it
# pip install -U pip setuptools wheel
# pip install iotics-identity
# USER_KEY_NAME, AGENT_KEY_NAME, USER_SEED, AGENT_SEED

import json
from datetime import datetime, timedelta, timezone
from typing import List
from uuid import uuid4

from iotics.lib.identity.api.high_level_api import get_rest_high_level_identity_api
from requests import request

RESOLVER_URL = "resolver_url"
HOST = "host_url"

USER_KEY_NAME = "user_key_name"
AGENT_KEY_NAME = "agent_key_name"
USER_SEED = bytes.fromhex("user_seed")
AGENT_SEED = bytes.fromhex("agent_seed")


def search_twins(
    headers: dict,
    properties: List[dict] = None,
    text: str = None,
    location: dict = None,
    scope: str = "GLOBAL",
    response_type: str = "FULL",
):
    payload = {"filter": {}, "responseType": response_type}

    if properties:
        payload["filter"]["properties"] = properties
    if text:
        payload["filter"]["text"] = text
    if location:
        payload["filter"]["location"] = location

    twins_list = []  # Initialise an empty list

    with request(
        method="POST",
        url=f"{HOST}/qapi/searches",
        headers=headers,
        json=payload,
        stream=True,
        verify=False,
        params={"scope": scope},
    ) as resp:
        # Raises HTTPError, if one occurred
        resp.raise_for_status()
        # Iterates over the response data, one line at a time
        for chunk in resp.iter_lines():
            response = json.loads(chunk)
            twins_found = []
            try:
                host_id = response["result"]["payload"]["remoteHostId"]["value"]
                twins_found = response["result"]["payload"]["twins"]
            except KeyError:
                host_id = "local"
            else:
                if twins_found:
                    # Add the host id value to each twin
                    for twin in twins_found:
                        twin["HostId"] = host_id

                    # Append the twins found to the list of twins
                    twins_list.extend(twins_found)

    return twins_list


def create_headers(client_app_id: uuid4, token: str, request_timeout: str):
    return {
        "accept": "application/json",
        "Iotics-ClientAppId": f"search_{client_app_id}",
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "Iotics-RequestTimeout": request_timeout,
    }


def create_property_dict(property_key: str, property_value: str, property_type: str):
    return {"key": property_key, property_type: {"value": property_value}}


def create_location_dict(lat: float, lon: float, radius_km: float):
    return {
        "location": {"lon": lon, "lat": lat},
        "radiusKm": radius_km,
    }


api = get_rest_high_level_identity_api(resolver_url=RESOLVER_URL)
(
    user_registered_id,
    agent_registered_id,
) = api.create_user_and_agent_with_auth_delegation(
    user_seed=USER_SEED,
    user_key_name=USER_KEY_NAME,
    agent_seed=AGENT_SEED,
    agent_key_name=AGENT_KEY_NAME,
    delegation_name="#AuthDeleg",
)

twins_list = search_twins(
    headers=create_headers(
        client_app_id=uuid4(),
        token=api.create_agent_auth_token(
            agent_registered_identity=agent_registered_id,
            user_did=user_registered_id.did,
            duration=30,
        ),
        request_timeout=(
            datetime.now(tz=timezone.utc) + timedelta(seconds=10)
        ).isoformat(),
    ),
    properties=[
        create_property_dict(
            property_key="http://data.iotics.com/public#hostAllowList",
            property_type="uriValue",
            property_value="http://data.iotics.com/public#allHosts",
        )
    ],
    location=create_location_dict(lat=52.205276, lon=0.119167, radius_km=3),
    text="Weather",
)

print(f"{len(twins_list)} twins found")
print("---")

for twin in twins_list:
    print(json.dumps(twin, indent=4))
    print("---")

Did this page help you?