i2 Connect SPI examples
You can use the following example requests and responses to help understand how parameterized and seeded search services work.
Example data
Throughout, assume you are querying the following set of entities and links.
The following are the type IDs corresponding to each of the entity, link and property types used in the example schema:
Entity | ID |
---|---|
Complaint | ET1 |
Location | ET2 |
Person | ET3 |
Link | ID |
---|---|
Located At | LT1 |
Suspect Of | LT2 |
Victim Of | LT3 |
Properties | For Entity | ID |
---|---|---|
Complaint Number | Complaint | PT1 |
Borough Name | Location | PT16 |
Age Group | Person | PT26 |
Race | Person | PT27 |
Gender | Person | PT28 |
This can be represented as a set of entities and links in JSON as follows:
{
"entities": [
{
"typeId": "ET1",
"id": "complaint-1",
"version": 1,
"properties": {
"PT1": "1",
}
},
{
"typeId": "ET2",
"id": "manhattan",
"version": 1,
"properties": {
"PT16": "MANHATTAN"
}
},
{
"typeId": "ET3",
"id": "person-A",
"version": 1,
"properties": {
"PT28": "M",
"PT26": "18-24",
"PT27": "White"
}
},
{
"typeId": "ET3",
"id": "person-B",
"version": 1,
"properties": {
"PT28": "M",
"PT26": "<18",
"PT27": "Black"
}
},
{
"typeId": "ET1",
"id": "complaint-2",
"version": 1,
"properties": {
"PT1": "2",
}
},
{
"typeId": "ET3",
"id": "person-C",
"version": 1,
"properties": {
"PT28": "F",
"PT26": "<18",
"PT27": "White"
}
},
{
"typeId": "ET3",
"id": "person-D",
"version": 1,
"properties": {
"PT28": "F",
"PT26": "<18",
"PT27": "White"
}
},
{
"typeId": "ET1",
"id": "complaint-3",
"version": 1,
"properties": {
"PT1": "3",
}
},
{
"typeId": "ET2",
"id": "bronx",
"version": 1,
"properties": {
"PT16": "BRONX"
}
},
{
"typeId": "ET3",
"id": "person-E",
"version": 1,
"properties": {
"PT28": "M",
"PT26": "18-24",
"PT27": "White"
}
},
{
"typeId": "ET3",
"id": "person-F",
"version": 1,
"properties": {
"PT28": "F",
"PT26": "45-64",
"PT27": "Black"
}
}
],
"links": [
{
"typeId": "LT1",
"id": "located-at-1",
"version": 1,
"fromEndId": "complaint-1",
"toEndId": "manhattan",
"linkDirection": "WITH",
},
{
"typeId": "LT2",
"id": "suspect-of-1",
"version": 1,
"fromEndId": "complaint-1",
"toEndId": "person-A",
"linkDirection": "WITH",
},
{
"typeId": "LT3",
"id": "victim-of-1",
"version": 1,
"fromEndId": "complaint-1",
"toEndId": "person-B",
"linkDirection": "WITH",
},
{
"typeId": "LT1",
"id": "located-at-2",
"version": 1,
"fromEndId": "complaint-2",
"toEndId": "bronx",
"linkDirection": "WITH",
},
{
"typeId": "LT2",
"id": "suspect-of-2",
"version": 1,
"fromEndId": "complaint-2",
"toEndId": "person-C",
"linkDirection": "WITH",
},
{
"typeId": "LT3",
"id": "victim-of-2",
"version": 1,
"fromEndId": "complaint-2",
"toEndId": "person-D",
"linkDirection": "WITH",
},
{
"typeId": "LT1",
"id": "located-at-3",
"version": 1,
"fromEndId": "complaint-3",
"toEndId": "bronx",
"linkDirection": "WITH",
},
{
"typeId": "LT2",
"id": "suspect-of-3",
"version": 1,
"fromEndId": "complaint-3",
"toEndId": "person-E",
"linkDirection": "WITH",
},
{
"typeId": "LT3",
"id": "victim-of-3",
"version": 1,
"fromEndId": "complaint-3",
"toEndId": "person-F",
"linkDirection": "WITH",
}
]
}
Parameterized search
To implement a service to search for people by age group, you can define a
clientConfig
in config.json
like the following:
{
"id": "age-search-form",
"type": "FORM",
"config": {
"sections": [
{
"conditions": [
{
"id": "age-group-search-term",
"label": "Age Group",
"logicalType": "SINGLE_LINE_STRING",
"mandatory": true
}
]
}
]
}
}
The id
should be a unique identifier for this clientConfig
. Then the services you define can use this form by supplying this id
in the service's clientConfigId
field.
The config
contains sections
and each section contains a JSON object defining a condition field depicted below:
- The condition
id
is used as a reference for the value in the request. - The
label
is the field title as shown in[1]
above. - The
logicalType
defines the accepted data type of the request value entry[2]
. - The
mandatory
field specifies whether a value is required for the field. Empty mandatory fields are highlighted red and shown a warning message[3]
.
A DaodRequest
issued by i2 Analyze when a user runs this search might look
like this:
{
"payload": {
"conditions": [
{
"id": "age-group-search",
"logicalType": "SINGLE_LINE_STRING",
"value": "18-24"
}
],
"seeds": {}
}
}
The request searches for Person entities where the Age Group property is equal to "18-24".
In the implementation of the parameterized search service, you would filter through the data and find entities which satisfy the request
requirements, i.e. have typeId
equal to "ET3"
and have the Age Group property PT26
equal to "18-24"
.
The response, from the example request above, would look like this:
{
"entities": [
{
"typeId": "ET3",
"id": "person-A",
"version": 1,
"properties": {
"PT28": "M",
"PT26": "18-24",
"PT27": "White"
}
},
{
"typeId": "ET3",
"id": "person-E",
"version": 1,
"properties": {
"PT28": "M",
"PT26": "18-24",
"PT27": "White"
}
}
],
"links": []
}
Seeded search
Seeded searches take as input a set of entities and links that a user already has on their chart and use this information when finding results. The types of seeded search operations that the following examples cover are:
"Find like this", where a user is able to select a single entity and search for other entities of the same type with similar properties.
"Expand", where a user can select an entity on their chart and search for all other entities that are connected to it by a link, and all those entities and links will be returned.
Note: The requests in these examples do not include data from semantic seeds. For an example of a request that does contain such data, see Semantic seeds.
Find like this
A DaodRequest
received by the connector for a "find like this" search on the example data could look something like the following:
{
"payload": {
"conditions": {},
"seeds": {
"entities": [
{
"accessDimensionValues": [],
"extensions": [],
"label": "",
"properties": {
"PT28": "F",
"PT26": "<18",
"PT27": "White"
},
"seedId": "d8ee0564-57bb-40ed-9409-79f8d13497a5",
"sourceIds": [
{
"key": ["nypd-connector", "ET3", "person-D"],
"type": "OI.DAOD"
}
],
"typeId": "ET3"
}
],
"links": [],
"allItemTypes": []
}
}
}
You can deduce which of the entities the DaodSeedEntity
in this request corresponds to by looking at the key in the sourceIds
field.
The third element of this list gives us the ID we have assigned the entity in our connector, "person-D"
.
You also have its type ID "ET3"
, so it is a Person entity.
Have a look at the data above and find this entity.
To perform a "find like this" search using this seed entity, you need only use its properties.
We can filter through our list of entities for those which have typeId
equal to "ET3"
(are Person entities) and have the properties:
PT26
equal to"F"
, i.e. they are female;PT27
equal to"White"
, i.e. they are a white female; andPT28
equal to"<18"
, i.e. they are a white female under 18 years of age.
After excluding the seed entity itself, you would return the following:
{
"entities": [
{
"typeId": "ET3",
"id": "person-C",
"version": 1,
"properties": {
"PT28": "F",
"PT26": "<18",
"PT27": "White"
}
}
],
"links": []
}
Expand
A DaodRequest
received by the connector for an "expand" search might look like this:
{
"payload": {
"conditions": {},
"seeds": {
"entities": [
{
"accessDimensionValues": [],
"extensions": [],
"label": "",
"properties": {
"PT1": "1",
},
"seedId": "1e756171-fb3c-40a4-b7c5-5c537fbf0adc",
"sourceIds": [
{
"key": ["nypd-connector", "ET1", "complaint-1"],
"type": "OI.DAOD"
}
],
"typeId": "ET1"
}
],
"links": [],
"allItemTypes": []
}
}
}
Again, you can deduce which of our entities the DaodSeedEntity
corresponds to by looking at the sourceIds
.
The id
of the entity in question is "complaint-1"
and it has typeID
equal to "ET1"
, so it is a complaint.
Look at the example data above and find which entity you are expanding.
What would you expect an Expand operation to return?
To perform an Expand operation with this entity as the seed, you need to:
Find all links connected to the corresponding entity. This means going through all the links and finding those with a
fromEndId
or atoEndId
equal to theid
of the entity,"person-D"
.Find all entities at the other end of these links. This can be done by using the
fromEndId
s andtoEndId
s of the links found in step 1 - just use the end ID that does not correspond to the seed entity.
If returning these entities and links as-is, along with the entity corresponding to the seed, you would respond with:
{
"entities": [
{
"typeId": "ET1",
"id": "complaint-1",
"version": 1,
"properties": {
"PT1": "1",
}
},
{
"typeId": "ET2",
"id": "manhattan",
"version": 1,
"properties": {
"PT16": "MANHATTAN"
}
},
{
"typeId": "ET3",
"id": "person-A",
"version": 1,
"properties": {
"PT28": "M",
"PT26": "18-24",
"PT27": "White"
}
},
{
"typeId": "ET3",
"id": "person-B",
"version": 1,
"properties": {
"PT28": "M",
"PT26": "<18",
"PT27": "Black"
}
}
],
"links": [
{
"typeId": "LT1",
"id": "located-at-1",
"version": 1,
"fromEndId": "complaint-1",
"toEndId": "manhattan",
"linkDirection": "WITH",
},
{
"typeId": "LT2",
"id": "suspect-of-1",
"version": 1,
"fromEndId": "complaint-1",
"toEndId": "person-A",
"linkDirection": "WITH",
},
{
"typeId": "LT3",
"id": "victim-of-1",
"version": 1,
"fromEndId": "complaint-1",
"toEndId": "person-B",
"linkDirection": "WITH",
}
]
}
When copying these results to a chart, the seed entity would be duplicated along with all its links and connected entities that may already be on the chart which would all be connected to the duplicate.
Depending on how you want the service to function, you might prefer to have the returned items connected to the entity that you selected on the chart rather than to a duplicate.
In this case, you need to change all id
, fromEndId
and toEndId
fields that refer to the ID of the seed entity (in this case "complaint-1") to seedId
of the DaodSeedEntity
in the request, i.e. "1e756171-fb3c-40a4-b7c5-5c537fbf0adc"
.
In this case, you would return the following response:
{
"entities": [
{
"typeId": "ET2",
"id": "manhattan",
"version": 1,
"properties": {
"PT16": "MANHATTAN"
}
},
{
"typeId": "ET3",
"id": "person-A",
"version": 1,
"properties": {
"PT28": "M",
"PT26": "18-24",
"PT27": "White"
}
},
{
"typeId": "ET3",
"id": "person-B",
"version": 1,
"properties": {
"PT28": "M",
"PT26": "<18",
"PT27": "Black"
}
}
],
"links": [
{
"typeId": "LT1",
"id": "located-at-1",
"version": 1,
"fromEndId": "1e756171-fb3c-40a4-b7c5-5c537fbf0adc",
"toEndId": "manhattan",
"linkDirection": "WITH",
},
{
"typeId": "LT2",
"id": "suspect-of-1",
"version": 1,
"fromEndId": "1e756171-fb3c-40a4-b7c5-5c537fbf0adc",
"toEndId": "person-A",
"linkDirection": "WITH",
},
{
"typeId": "LT3",
"id": "victim-of-1",
"version": 1,
"fromEndId": "1e756171-fb3c-40a4-b7c5-5c537fbf0adc",
"toEndId": "person-B",
"linkDirection": "WITH",
}
]
}