Skip to content

Commit

Permalink
issue #1708 use ibm-internal stored parameters for compartment searches
Browse files Browse the repository at this point in the history
Signed-off-by: Robin Arnold <robin.arnold23@ibm.com>
  • Loading branch information
punktilious committed Nov 19, 2020
1 parent 398bbdc commit 2d89c8a
Show file tree
Hide file tree
Showing 11 changed files with 669 additions and 20 deletions.
17 changes: 16 additions & 1 deletion docs/src/pages/guides/FHIRServerUsersGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ Configuration properties stored within a `fhir-server-config.json` file are stru
Throughout this document, we use a path notation to refer to property names. For example, the name of the `defaultPrettyPrint` property in the preceding example would be `fhirServer/core/defaultPrettyPrint`.
## 3.3 Tenant-specific configuration properties
The FHIR server supports certain multi-tenant features. One such feature is the ability to set certain configuration properties on a per-tenant basis.
The IBM FHIR server supports certain multi-tenant features. One such feature is the ability to set certain configuration properties on a per-tenant basis.
In general, the configuration properties for a particular tenant are stored in the `<WLP_HOME>/usr/servers/fhir-server/config/<tenant-id>/fhir-server-config.json` file, where `<tenant-id>` refers to the tenant's “short name” or tenant id.
Expand All @@ -171,6 +171,20 @@ Search parameters are handled like a single configuration properly; providing a
More information about multi-tenant support can be found in [Section 4.9 Multi-tenancy](#49-multi-tenancy).
## 3.3.1 Compartment Search Performance
The IBM FHIR Server now supports the ability to compute and store compartment membership values during ingestion. Once stored, these values can help accelerate compartment-related search queries. To use this feature, update the IBM FHIR Server to the latest version and run a reindex operation. See the release notes for Release 4.5.0 for details. The reindex operation reprocesses the resources stored in the database, computing and storing the new compartment reference values. After the reindex operation has completed, add the following configuration element to the relevant tenant fhir-server-config.json file to allow the search queries to use the pre-computed values:
```
{
"fhirServer": {
"search": {
"useStoredCompartmentParam": true
}
}
}
```
## 3.4 Persistence layer configuration
The IBM FHIR server allows deployers to select a persistence layer implementation that fits their needs. Currently, the server includes a JDBC persistence layer which supports Apache Derby, IBM Db2, and PostgreSQL. However, Apache Derby is not recommended for production usage.
Expand Down Expand Up @@ -1848,6 +1862,7 @@ This section contains reference information about each of the configuration prop
|`fhirServer/audit/serviceProperties/geoState`|string|The Geo State configure for CADF audit logging service.|
|`fhirServer/audit/serviceProperties/geoCounty`|string|The Geo Country configure for CADF audit logging service.|
|`fhirServer/search/useBoundingRadius`|boolean|True, the bounding area is a Radius, else the bounding area is a box.|
|`fhirServer/search/useStoredCompartmentParam`|boolean|False, Compute and store parameter to accelerate compartment searches. Requires reindex using latest IBM FHIR Server version before this feature is enabled |
|`fhirServer/bulkdata/applicationName`| string|Fixed value, always set to fhir-bulkimportexport-webapp |
|`fhirServer/bulkdata/moduleName`|string| Fixed value, always set to fhir-bulkimportexport.war |
|`fhirServer/bulkdata/jobParameters/cos.bucket.name`|string|Object store bucket name |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class FHIRConfiguration {
public static final String PROPERTY_FIELD_RESOURCES_SEARCH_PARAMETER_COMBINATIONS = "searchParameterCombinations";
public static final String PROPERTY_FIELD_RESOURCES_PROFILES = "profiles";
public static final String PROPERTY_FIELD_RESOURCES_PROFILES_AT_LEAST_ONE = "atLeastOne";
public static final String PROPERTY_USE_STORED_COMPARTMENT_PARAM = "fhirServer/search/useStoredCompartmentParam";

// Auth and security properties
public static final String PROPERTY_SECURITY_CORS = "fhirServer/security/cors";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"resourceType": "Basic",
"code": {
"text": "test"
},
"author": {
"reference": "Patient/123"
},
"extension": [
{
"url": "http://example.org/uri",
"valueUri": "urn:uuid:53fefa32-1111-2222-3333-55ee120877b7"
},
{
"url": "http://example.org/Reference",
"valueReference": {
"reference": "Basic/123"
}
},
{
"url": "http://example.org/Reference-id",
"valueReference": {
"identifier": {
"system": "http://example.org/identifier",
"value": "123"
}
}
},
{
"url": "http://example.org/Reference-relative",
"valueReference": {
"reference": "Patient/123"
}
},
{
"url": "http://example.org/Reference-absolute",
"valueReference": {
"reference": "https://example.com/Patient/123"
}
},
{
"url": "http://example.org/Reference-display",
"valueReference": {
"display": "text alternative for the resource"
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -1475,7 +1475,11 @@ private List<ExtractedParameterValue> extractSearchParameters(Resource fhirResou
}

/**
* Augment the given list with additional reference values
* Augment the given allParameters list with ibm-internal parameters represents relationships
* of the fhirResource to its compartments. These parameter values are subsequently used
* to improve the performance of compartment-based FHIR search queries. See
* {@link CompartmentUtil#makeCompartmentParamName(String)} for details on how the
* parameter name is composed for each relationship.
* @param allParameters
*/
protected void addCompartmentParams(List<ExtractedParameterValue> allParameters, Resource fhirResource) throws FHIRSearchException {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* (C) Copyright IBM Corp. 2020
*
* SPDX-License-Identifier: Apache-2.0
*/

package com.ibm.fhir.persistence.jdbc.search.test;

import java.util.Properties;

import com.ibm.fhir.database.utils.api.IConnectionProvider;
import com.ibm.fhir.database.utils.pool.PoolConnectionProvider;
import com.ibm.fhir.model.test.TestUtil;
import com.ibm.fhir.persistence.FHIRPersistence;
import com.ibm.fhir.persistence.jdbc.FHIRPersistenceJDBCCache;
import com.ibm.fhir.persistence.jdbc.cache.CommonTokenValuesCacheImpl;
import com.ibm.fhir.persistence.jdbc.cache.FHIRPersistenceJDBCCacheImpl;
import com.ibm.fhir.persistence.jdbc.cache.NameIdCache;
import com.ibm.fhir.persistence.jdbc.dao.api.ICommonTokenValuesCache;
import com.ibm.fhir.persistence.jdbc.impl.FHIRPersistenceJDBCImpl;
import com.ibm.fhir.persistence.jdbc.test.util.DerbyInitializer;
import com.ibm.fhir.persistence.search.test.AbstractSearchCompartmentTest;

/**
* JDBC unit-tests for compartment-based searches
*/
public class JDBCSearchCompartmentTest extends AbstractSearchCompartmentTest {

private Properties testProps;

private PoolConnectionProvider connectionPool;

private FHIRPersistenceJDBCCache cache;

public JDBCSearchCompartmentTest() throws Exception {
this.testProps = TestUtil.readTestProperties("test.jdbc.properties");
}

@Override
public void bootstrapDatabase() throws Exception {
DerbyInitializer derbyInit;
String dbDriverName = this.testProps.getProperty("dbDriverName");
if (dbDriverName != null && dbDriverName.contains("derby")) {
derbyInit = new DerbyInitializer(this.testProps);
IConnectionProvider cp = derbyInit.getConnectionProvider(false);
this.connectionPool = new PoolConnectionProvider(cp, 1);
ICommonTokenValuesCache rrc = new CommonTokenValuesCacheImpl(100, 100);
cache = new FHIRPersistenceJDBCCacheImpl(new NameIdCache<Integer>(), new NameIdCache<Integer>(), rrc);
}
}

@Override
public FHIRPersistence getPersistenceImpl() throws Exception {
if (this.connectionPool == null) {
throw new IllegalStateException("Database not bootstrapped");
}
return new FHIRPersistenceJDBCImpl(this.testProps, this.connectionPool, cache);
}

@Override
protected void shutdownPools() throws Exception {
// Mark the pool as no longer in use. This allows the pool to check for
// lingering open connections/transactions.
if (this.connectionPool != null) {
this.connectionPool.close();
}
}
}
1 change: 1 addition & 0 deletions fhir-persistence-jdbc/src/test/java/testng.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
</test>
<test name="JDBCSearchTests">
<classes>
<class name="com.ibm.fhir.persistence.jdbc.search.test.JDBCSearchCompartmentTest" />
<class name="com.ibm.fhir.persistence.jdbc.search.test.JDBCSearchCompositeTest" />
<class name="com.ibm.fhir.persistence.jdbc.search.test.JDBCSearchDateTest" />
<class name="com.ibm.fhir.persistence.jdbc.search.test.JDBCSearchNumberTest" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* (C) Copyright IBM Corp. 2020
*
* SPDX-License-Identifier: Apache-2.0
*/

package com.ibm.fhir.persistence.search.test;

import static org.testng.AssertJUnit.assertEquals;

import java.util.List;

import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import com.ibm.fhir.config.FHIRRequestContext;
import com.ibm.fhir.exception.FHIRException;
import com.ibm.fhir.model.resource.Basic;
import com.ibm.fhir.model.resource.Resource;
import com.ibm.fhir.model.test.TestUtil;

/**
* Unit tests for compartment-based searches
* @see https://hl7.org/fhir/r4/search.html
* GET [base]/Patient/[id]/[type]?parameter(s)
*/
public abstract class AbstractSearchCompartmentTest extends AbstractPLSearchTest {

@Override
protected Basic getBasicResource() throws Exception {
return TestUtil.readExampleResource("json/ibm/basic/BasicCompartment.json");
}

@Override
protected void setTenant() throws Exception {
FHIRRequestContext.get().setTenantId("compartment");

// Need to set reference before storing the resource. The server-url
// is now used to determine if an absolute reference is local (can be served
// from this FHIR server).
createReference();
}

@BeforeClass
public void createReference() throws FHIRException {
String originalRequestUri = "https://example.com/Patient/123";
FHIRRequestContext context = FHIRRequestContext.get();
context.setOriginalRequestUri(originalRequestUri);
}

@Test
public void testSearchCompartment() throws Exception {
// The saved Basic resource is a member of the compartment Patient/123
// Check that we can find the resource with additional query parameters
// Note that "Reference-relative just happens to be another searchable
// parameter in the BasicCompartment.json resource
List<Resource> results = runQueryTest("Patient", "123",
Basic.class, "Reference-relative", "Patient/123");
assertEquals(1, results.size());
}
}
Loading

0 comments on commit 2d89c8a

Please sign in to comment.