Use separate index columns

This commit is contained in:
James Agnew 2016-03-15 10:35:24 -04:00
parent 96d6fa1b8a
commit 9c8d9db7e6
16 changed files with 194 additions and 52 deletions

View File

@ -1225,15 +1225,22 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
for (IBaseReference nextRef : allRefs) { for (IBaseReference nextRef : allRefs) {
IIdType nextId = nextRef.getReferenceElement(); IIdType nextId = nextRef.getReferenceElement();
String nextIdText = nextId.getValue(); String nextIdText = nextId.getValue();
if (nextIdText == null) {
continue;
}
int qmIndex = nextIdText.indexOf('?'); int qmIndex = nextIdText.indexOf('?');
if (qmIndex != -1) { if (qmIndex != -1) {
for (int i = qmIndex - 1; i >= 0; i--) { for (int i = qmIndex - 1; i >= 0; i--) {
if (nextIdText.charAt(i) == '/') { if (nextIdText.charAt(i) == '/') {
if (i < nextIdText.length() - 1 && nextIdText.charAt(i + 1) == '?') {
// Just in case the URL is in the form Patient/?foo=bar
continue;
}
nextIdText = nextIdText.substring(i + 1); nextIdText = nextIdText.substring(i + 1);
break; break;
} }
} }
String resourceTypeString = nextIdText.substring(0, nextIdText.indexOf('?')); String resourceTypeString = nextIdText.substring(0, nextIdText.indexOf('?')).replace("/", "");
RuntimeResourceDefinition matchResourceDef = getContext().getResourceDefinition(resourceTypeString); RuntimeResourceDefinition matchResourceDef = getContext().getResourceDefinition(resourceTypeString);
if (matchResourceDef == null) { if (matchResourceDef == null) {
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlInvalidResourceType", nextId.getValue(), resourceTypeString); String msg = getContext().getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlInvalidResourceType", nextId.getValue(), resourceTypeString);

View File

@ -1,25 +1,5 @@
package ca.uhn.fhir.jpa.dao; package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.ArrayList; import java.util.ArrayList;

View File

@ -40,11 +40,6 @@ public abstract class BaseResourceIndexedSearchParam implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "SP_ID")
private Long myId;
@Field @Field
@Column(name = "SP_NAME", length = MAX_SP_NAME, nullable = false) @Column(name = "SP_NAME", length = MAX_SP_NAME, nullable = false)
private String myParamName; private String myParamName;
@ -61,9 +56,7 @@ public abstract class BaseResourceIndexedSearchParam implements Serializable {
@Column(name = "RES_TYPE", nullable = false) @Column(name = "RES_TYPE", nullable = false)
private String myResourceType; private String myResourceType;
protected Long getId() { protected abstract Long getId();
return myId;
}
public String getParamName() { public String getParamName() {
return myParamName; return myParamName;

View File

@ -55,8 +55,8 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id @Id
@GeneratedValue(strategy = GenerationType.AUTO) @SequenceGenerator(name = "SEQ_RESOURCE_HISTORY_ID", sequenceName = "SEQ_RESOURCE_HISTORY_ID")
@SequenceGenerator(name = "RES_HISTORY_PID", sequenceName = "RES_HISTORY_PID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESOURCE_HISTORY_ID")
@Column(name = "PID") @Column(name = "PID")
private Long myId; private Long myId;

View File

@ -23,7 +23,11 @@ package ca.uhn.fhir.jpa.entity;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index; import javax.persistence.Index;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
@ -45,6 +49,12 @@ public class ResourceIndexedSearchParamCoords extends BaseResourceIndexedSearchP
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name = "SEQ_SPIDX_COORDS", sequenceName = "SEQ_SPIDX_COORDS")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_COORDS")
@Column(name = "SP_ID")
private Long myId;
@Column(name = "SP_LATITUDE") @Column(name = "SP_LATITUDE")
@Field @Field
public double myLatitude; public double myLatitude;
@ -82,6 +92,11 @@ public class ResourceIndexedSearchParamCoords extends BaseResourceIndexedSearchP
return b.isEquals(); return b.isEquals();
} }
@Override
protected Long getId() {
return myId;
}
public double getLatitude() { public double getLatitude() {
return myLatitude; return myLatitude;
} }

View File

@ -25,6 +25,10 @@ import java.util.Date;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
@ -47,6 +51,12 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name = "SEQ_SPIDX_DATE", sequenceName = "SEQ_SPIDX_DATE")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_DATE")
@Column(name = "SP_ID")
private Long myId;
@Column(name = "SP_VALUE_HIGH", nullable = true) @Column(name = "SP_VALUE_HIGH", nullable = true)
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
@Field @Field
@ -92,6 +102,11 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar
return b.isEquals(); return b.isEquals();
} }
@Override
protected Long getId() {
return myId;
}
public Date getValueHigh() { public Date getValueHigh() {
return myValueHigh; return myValueHigh;
} }

View File

@ -25,6 +25,10 @@ import java.math.BigDecimal;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
@ -49,6 +53,12 @@ public class ResourceIndexedSearchParamNumber extends BaseResourceIndexedSearchP
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name = "SEQ_SPIDX_NUMBER", sequenceName = "SEQ_SPIDX_NUMBER")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_NUMBER")
@Column(name = "SP_ID")
private Long myId;
@Column(name = "SP_VALUE", nullable = true) @Column(name = "SP_VALUE", nullable = true)
@Field @Field
@NumericField @NumericField
@ -82,6 +92,11 @@ public class ResourceIndexedSearchParamNumber extends BaseResourceIndexedSearchP
return b.isEquals(); return b.isEquals();
} }
@Override
protected Long getId() {
return myId;
}
public BigDecimal getValue() { public BigDecimal getValue() {
return myValue; return myValue;
} }

View File

@ -25,6 +25,10 @@ import java.math.BigDecimal;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
@ -51,6 +55,12 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name = "SEQ_SPIDX_QUANTITY", sequenceName = "SEQ_SPIDX_QUANTITY")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_QUANTITY")
@Column(name = "SP_ID")
private Long myId;
@Column(name = "SP_SYSTEM", nullable = true, length = MAX_LENGTH) @Column(name = "SP_SYSTEM", nullable = true, length = MAX_LENGTH)
@Field @Field
public String mySystem; public String mySystem;
@ -97,6 +107,11 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
return b.isEquals(); return b.isEquals();
} }
@Override
protected Long getId() {
return myId;
}
public String getSystem() { public String getSystem() {
return mySystem; return mySystem;
} }

View File

@ -23,8 +23,12 @@ package ca.uhn.fhir.jpa.entity;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -101,6 +105,17 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name="SEQ_SPIDX_STRING", sequenceName="SEQ_SPIDX_STRING")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_STRING")
@Column(name = "SP_ID")
private Long myId;
@ManyToOne(optional = false)
@JoinColumn(name = "RES_ID", referencedColumnName="RES_ID", insertable=false, updatable=false)
@ContainedIn
private ResourceTable myResourceTable;
@Column(name = "SP_VALUE_EXACT", length = MAX_LENGTH, nullable = true) @Column(name = "SP_VALUE_EXACT", length = MAX_LENGTH, nullable = true)
@Fields({ @Fields({
@Field(name = "myValueText", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "standardAnalyzer")), @Field(name = "myValueText", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "standardAnalyzer")),
@ -113,15 +128,10 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
@Column(name = "SP_VALUE_NORMALIZED", length = MAX_LENGTH, nullable = true) @Column(name = "SP_VALUE_NORMALIZED", length = MAX_LENGTH, nullable = true)
private String myValueNormalized; private String myValueNormalized;
@ManyToOne(optional = false)
@JoinColumn(name = "RES_ID", referencedColumnName="RES_ID", insertable=false, updatable=false)
@ContainedIn
private ResourceTable myResourceTable;
public ResourceIndexedSearchParamString() { public ResourceIndexedSearchParamString() {
} }
public ResourceIndexedSearchParamString(String theName, String theValueNormalized, String theValueExact) { public ResourceIndexedSearchParamString(String theName, String theValueNormalized, String theValueExact) {
setParamName(theName); setParamName(theName);
setValueNormalized(theValueNormalized); setValueNormalized(theValueNormalized);
@ -147,6 +157,11 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
return b.isEquals(); return b.isEquals();
} }
@Override
protected Long getId() {
return myId;
}
public String getValueExact() { public String getValueExact() {
return myValueExact; return myValueExact;
} }

View File

@ -23,6 +23,10 @@ package ca.uhn.fhir.jpa.entity;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -43,6 +47,12 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name = "SEQ_SPIDX_TOKEN", sequenceName = "SEQ_SPIDX_TOKEN")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_TOKEN")
@Column(name = "SP_ID")
private Long myId;
@Field() @Field()
@Column(name = "SP_SYSTEM", nullable = true, length = MAX_LENGTH) @Column(name = "SP_SYSTEM", nullable = true, length = MAX_LENGTH)
public String mySystem; public String mySystem;
@ -80,6 +90,11 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa
return b.isEquals(); return b.isEquals();
} }
@Override
protected Long getId() {
return myId;
}
public String getSystem() { public String getSystem() {
return mySystem; return mySystem;
} }

View File

@ -23,7 +23,11 @@ package ca.uhn.fhir.jpa.entity;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index; import javax.persistence.Index;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -49,6 +53,12 @@ public class ResourceIndexedSearchParamUri extends BaseResourceIndexedSearchPara
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name="SEQ_SPIDX_URI", sequenceName="SEQ_SPIDX_URI")
@GeneratedValue(strategy = GenerationType.AUTO, generator="SEQ_SPIDX_URI")
@Column(name = "SP_ID")
private Long myId;
@Column(name = "SP_URI", nullable = true, length = MAX_LENGTH) @Column(name = "SP_URI", nullable = true, length = MAX_LENGTH)
@Field() @Field()
public String myUri; public String myUri;
@ -80,6 +90,11 @@ public class ResourceIndexedSearchParamUri extends BaseResourceIndexedSearchPara
return b.isEquals(); return b.isEquals();
} }
@Override
protected Long getId() {
return myId;
}
public String getUri() { public String getUri() {
return myUri; return myUri;
} }

View File

@ -36,6 +36,7 @@ import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.Index; import javax.persistence.Index;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Transient; import javax.persistence.Transient;
@ -144,14 +145,12 @@ public class ResourceTable extends BaseHasResource implements Serializable {
//@formatter:on //@formatter:on
private String myContentText; private String myContentText;
@Column(name = "HAS_CONTAINED", nullable = true)
private boolean myHasContainedResource;
@Column(name = "SP_HAS_LINKS") @Column(name = "SP_HAS_LINKS")
private boolean myHasLinks; private boolean myHasLinks;
@Id @Id
@GeneratedValue(strategy = GenerationType.AUTO) @SequenceGenerator(name="SEQ_RESOURCE_ID", sequenceName="SEQ_RESOURCE_ID")
@GeneratedValue(strategy = GenerationType.AUTO, generator="SEQ_RESOURCE_ID")
@Column(name = "RES_ID") @Column(name = "RES_ID")
private Long myId; private Long myId;
@ -346,10 +345,6 @@ public class ResourceTable extends BaseHasResource implements Serializable {
return false; return false;
} }
public boolean isHasContainedResource() {
return myHasContainedResource;
}
public boolean isHasLinks() { public boolean isHasLinks() {
return myHasLinks; return myHasLinks;
} }
@ -390,10 +385,6 @@ public class ResourceTable extends BaseHasResource implements Serializable {
myContentText = theContentText; myContentText = theContentText;
} }
public void setHasContainedResource(boolean theHasContainedResource) {
myHasContainedResource = theHasContainedResource;
}
public void setHasLinks(boolean theHasLinks) { public void setHasLinks(boolean theHasLinks) {
myHasLinks = theHasLinks; myHasLinks = theHasLinks;
} }

View File

@ -345,6 +345,40 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
@Test
public void testTransactionCreateInlineMatchUrlWithOneMatch2() {
String methodName = "testTransactionCreateInlineMatchUrlWithOneMatch2";
Bundle request = new Bundle();
myDaoConfig.setAllowInlineMatchUrlReferences(true);
Patient p = new Patient();
p.addName().addGiven("Heute");
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IIdType id = myPatientDao.update(p, mySrd).getId();
ourLog.info("Created patient, got it: {}", id);
Observation o = new Observation();
o.getCode().setText("Some Observation");
o.getSubject().setReference("Patient/?given=heute");
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
Bundle resp = mySystemDao.transaction(myRequestDetails, request);
assertEquals(1, resp.getEntry().size());
BundleEntryComponent respEntry = resp.getEntry().get(0);
assertEquals(Constants.STATUS_HTTP_201_CREATED + " Created", respEntry.getResponse().getStatus());
assertThat(respEntry.getResponse().getLocation(), containsString("Observation/"));
assertThat(respEntry.getResponse().getLocation(), endsWith("/_history/1"));
assertEquals("1", respEntry.getResponse().getEtag());
o = myObservationDao.read(new IdType(respEntry.getResponse().getLocationElement()), mySrd);
assertEquals(id.toVersionless().getValue(), o.getSubject().getReference());
assertEquals("1", o.getIdElement().getVersionIdPart());
}
@Test @Test
public void testTransactionCreateInlineMatchUrlWithNoMatches() { public void testTransactionCreateInlineMatchUrlWithNoMatches() {
String methodName = "testTransactionCreateInlineMatchUrlWithNoMatches"; String methodName = "testTransactionCreateInlineMatchUrlWithNoMatches";

View File

@ -116,6 +116,32 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
myDaoConfig.setAllowMultipleDelete(true); myDaoConfig.setAllowMultipleDelete(true);
} }
@Test
public void testCreateConditional() {
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
patient.addName().addFamily("Tester").addGiven("Raghad");
MethodOutcome output1 = ourClient
.update()
.resource(patient)
.conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100")
.execute();
patient = new Patient();
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
patient.addName().addFamily("Tester").addGiven("Raghad");
MethodOutcome output2 = ourClient
.update()
.resource(patient)
.conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100")
.execute();
assertEquals(output1.getId().getIdPart(), output2.getId().getIdPart());
}
private void checkParamMissing(String paramName) throws IOException, ClientProtocolException { private void checkParamMissing(String paramName) throws IOException, ClientProtocolException {
HttpGet get = new HttpGet(ourServerBase + "/Observation?" + paramName + ":missing=false"); HttpGet get = new HttpGet(ourServerBase + "/Observation?" + paramName + ":missing=false");
CloseableHttpResponse resp = ourHttpClient.execute(get); CloseableHttpResponse resp = ourHttpClient.execute(get);

View File

@ -136,7 +136,7 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
Set<TermConcept> concepts; Set<TermConcept> concepts;
Set<String> codes; Set<String> codes;
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "ChildAA"); concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAA");
codes = toCodes(concepts); codes = toCodes(concepts);
assertThat(codes, containsInAnyOrder("ParentA", "childAA")); assertThat(codes, containsInAnyOrder("ParentA", "childAA"));

View File

@ -241,6 +241,12 @@
first query. This should improve performance when searching against large first query. This should improve performance when searching against large
datasets. datasets.
</action> </action>
<action type="add">
JPA server database design has been adjusted
so that different tables use different sequences
to generate their indexes, resulting in more sequential
resource IDs being assigned by the server
<action>
</release> </release>
<release version="1.4" date="2016-02-04"> <release version="1.4" date="2016-02-04">
<action type="add"> <action type="add">