How-To: Custom Search Query
Target audience: Developers
Introduction
Sometimes, users will want to see slightly different data or data visualised in a different way than the default views. These default views, when you authenticate, show the instances (e.g. cases, processes and tasks) that you have permission on.
There is also an API with some default filters available to search work items (i.e. root case or process instances) or tasks with the filterId open
, all
, completed
, and mine
. However, sometimes there is no filter available which is giving you exactly what you would like to have.
In this case, Flowable offers you to create your own Elasticsearch query. In this howto, we'll show a basic example how such a custom query can be built.
There is also an advanced howto on indexing and search that covers advanced topics.
Creating an Own Query
Flowable has the capability to create your own queries, which is a powerful feature, and you should definitely check out the documentation on indexing to get a full overview of all additional possibilities with Flowable.
As an example, let's assume that we would like to search for all case instances with a given assignee.
Looking at our index (it's always a good idea to do this, this can be done by e.g. doing a call with Postman on http://localhost:9200/case-instances/_search
when running Elasticsearch on your local machine), we see for example the following structure:
{
"_index": "case-instances-20210213-2243-04-81784229",
"_type": "_doc",
"_id": "CAS-a3260edf-7453-11eb-9d47-1281fbfbc379",
"_version": 1,
"_seq_no": 0,
"_primary_term": 2,
"found": true,
"_source": {
"__flowableVersion": 8,
"caseDefinitionKey": "testCaseModel",
"caseDefinitionName": "Test Case Model",
"startUserId": "admin",
"startTime": "2021-02-21T14:46:53.322Z",
"id": "CAS-a3260edf-7453-11eb-9d47-1281fbfbc379",
"state": "active",
"involvedUsers": [
"admin"
],
"variables": [
{
"id": "VAR-a326d231-7453-11eb-9d47-1281fbfbc379",
"name": "initiator",
"type": "string",
"scopeId": "CAS-a3260edf-7453-11eb-9d47-1281fbfbc379",
"scopeType": "cmmn",
"scopeDefinitionId": "CAS-95dd54ea-7453-11eb-9d47-1281fbfbc379",
"scopeDefinitionKey": "testCaseModel",
"rawValue": "admin",
"textValue": "admin",
"textValueKeyword": "admin"
}
],
"caseDefinitionId": "CAS-95dd54ea-7453-11eb-9d47-1281fbfbc379",
"caseDefinitionCategory": "http://flowable.org/cmmn",
"identityLinks": [
{
"id": "IDL-a3276e72-7453-11eb-9d47-1281fbfbc379",
"type": "assignee",
"userId": "admin"
},
{
"id": "IDL-a3359f47-7453-11eb-9d47-1281fbfbc379",
"type": "participant",
"userId": "admin"
},
{
"id": "IDL-a3276e73-7453-11eb-9d47-1281fbfbc379",
"type": "owner",
"userId": "admin"
},
{
"id": "IDL-a32635f0-7453-11eb-9d47-1281fbfbc379",
"type": "starter",
"userId": "admin"
}
],
"tenantId": "default"
}
}
We can see that our indexed document will have a nested identityLinks
object.
We can use this part of the document to search for our cases.
There must be an entry with the userId
equal to our assignee we are searching for, and the type
of the field assignee
.
This can be easily achieved with the following Elasticsearch query:
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "identityLinks",
"query": {
"bool": {
"must": [
{
"term": {
"identityLinks.type": "assignee"
}
},
{
"term": {
"identityLinks.userId": "admin"
}
}
]
}
}
}
}
]
}
}
}
Of course, this query would only find the cases with the assignee admin
.
We can replace admin
with whatever we want to search for.
Using the Query in Flowable
Going against Elasticsearch gives you now a different document structure than what you might be used to from Flowable. Also, you are accessing Flowables Elasticsearch without going through Flowable.
This means that you are losing the out-of-the-box access control which is built into Flowable. To avoid that, Flowable provides the possibility to query with your custom queries.
To create your own query you need to put a document on your classpath in the directory com/flowable/indexing/mapping-extension/custom/
with the filename suffix .json
.
In this document, you have the following structure:
{
"key": "the-key-of-this-query",
"type": "query",
"sourceIndex": "case-instances",
"version": 1,
"parameters": {...},
"customFilter": {...}
}
The key
needs to be a system-unique identiefier for your query.
You can use the key
to describe the query with a name which can be used later to perform the search.
This query will use the case-instances
index, since we specified that as sourceIndex
.
The field parameters
allows us to specify custom parameters a user can pass in.
Inside customFilter
, we can specify our query.
Now, using our Elasticsearch query and combining this with our template structure, we can create a file com/flowable/indexing/mapping-extension/custom/case-by-assignee.json
on the classpath and put the following content inside:
{
"key": "case-by-assignee",
"type": "query",
"sourceIndex": "case-instances",
"version": 1,
"parameters": {
"assignee": "string"
},
"customFilter": {
"bool": {
"must": [
{
"nested": {
"path": "identityLinks",
"query": {
"bool": {
"must": [
{
"term": {
"identityLinks.type": "assignee"
}
},
{
"term": {
"identityLinks.userId": "{assignee}"
}
}
]
}
}
}
}
]
}
}
}
The userId
is now {assignee}
, which is exactly the same name as we have specified as a parameter
.
To make it available you need to restart your Flowable application.
Once this is done, we can execute a REST request to use our query:
/platform-api/search/query-case-instances/query/case-by-assignee?assignee=admin
.
As a result, we should see all case instances with the assignee admin
.
Further reading
This article has only shown a small part of the Elasticsearch integration. In addition to executing queries, it's also possible to extract variables, write your own content into the index, and enhance the output result. As a further resource, it's recommended to look into the Work Indexing documentation and the Advanced search How-To.