From ee4ca9c934dd8fb9b086e452020c24e170a38f54 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Thu, 5 Jun 2014 17:06:49 -0400 Subject: [PATCH] Performance enhancements on JPA history --- .../java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java | 33 +++-- .../ca/uhn/fhir/jpa/dao/FhirResourceDao.java | 11 +- .../ca/uhn/fhir/jpa/dao/HistoryTuple.java | 20 +-- .../fhir/jpa/entity/ResourceHistoryTable.java | 116 ++++++++++-------- .../jpa/entity/ResourceHistoryTablePk.java | 94 -------------- .../fhir/jpa/entity/ResourceHistoryTag.java | 12 +- .../ca/uhn/fhir/jpa/entity/ResourceTable.java | 8 +- 7 files changed, 103 insertions(+), 191 deletions(-) delete mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTablePk.java diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java index 51c8d88f731..d8fb97cbf16 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java @@ -35,7 +35,6 @@ import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.jpa.entity.BaseHasResource; import ca.uhn.fhir.jpa.entity.BaseTag; import ca.uhn.fhir.jpa.entity.ResourceHistoryTable; -import ca.uhn.fhir.jpa.entity.ResourceHistoryTablePk; import ca.uhn.fhir.jpa.entity.ResourceHistoryTag; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber; @@ -127,9 +126,9 @@ public abstract class BaseFhirDao { q.setMaxResults(myConfig.getHardSearchLimit()); } for (Tuple next : q.getResultList()) { - long id = (Long) next.get(0); - Date updated = (Date) next.get(1); - tuples.add(new HistoryTuple(ResourceTable.class, updated, id)); + long id = next.get(0, Long.class); + Date updated = next.get(1, Date.class); + tuples.add(new HistoryTuple(false, updated, id)); } } @@ -137,13 +136,13 @@ public abstract class BaseFhirDao { Collection tuples = Collections2.filter(theTuples, new com.google.common.base.Predicate() { @Override public boolean apply(HistoryTuple theInput) { - return theInput.getTable().equals(ResourceTable.class); + return theInput.isHistory() == false; } }); Collection ids = Collections2.transform(tuples, new Function() { @Override public Long apply(HistoryTuple theInput) { - return (Long) theInput.getId(); + return theInput.getId(); } }); if (ids.isEmpty()) { @@ -162,11 +161,11 @@ public abstract class BaseFhirDao { } } - private void searchHistoryHistory(String theResourceName, Long theId, Date theSince, Integer theLimit, List tuples) { + private void searchHistoryHistory(String theResourceName, Long theResourceId, Date theSince, Integer theLimit, List tuples) { CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); CriteriaQuery cq = builder.createTupleQuery(); Root from = cq.from(ResourceHistoryTable.class); - cq.multiselect(from.get("myPk").as(ResourceHistoryTablePk.class), from.get("myUpdated").as(Date.class)); + cq.multiselect(from.get("myId").as(Long.class), from.get("myUpdated").as(Date.class)); List predicates = new ArrayList(); if (theSince != null) { @@ -177,8 +176,8 @@ public abstract class BaseFhirDao { if (theResourceName != null) { predicates.add(builder.equal(from.get("myResourceType"), theResourceName)); } - if (theId != null) { - predicates.add(builder.equal(from.get("myId"), theId)); + if (theResourceId != null) { + predicates.add(builder.equal(from.get("myResourceId"), theResourceId)); } cq.where(builder.and(predicates.toArray(new Predicate[0]))); @@ -191,9 +190,9 @@ public abstract class BaseFhirDao { q.setMaxResults(myConfig.getHardSearchLimit()); } for (Tuple next : q.getResultList()) { - ResourceHistoryTablePk id = (ResourceHistoryTablePk) next.get(0); + Long id = next.get(0, Long.class); Date updated = (Date) next.get(1); - tuples.add(new HistoryTuple(ResourceHistoryTable.class, updated, id)); + tuples.add(new HistoryTuple(true, updated, id)); } } @@ -203,13 +202,13 @@ public abstract class BaseFhirDao { Collection tuples = Collections2.filter(theTuples, new com.google.common.base.Predicate() { @Override public boolean apply(HistoryTuple theInput) { - return theInput.getTable().equals(ResourceHistoryTable.class); + return theInput.isHistory()==true; } }); - Collection ids = Collections2.transform(tuples, new Function() { + Collection ids = Collections2.transform(tuples, new Function() { @Override - public ResourceHistoryTablePk apply(HistoryTuple theInput) { - return (ResourceHistoryTablePk) theInput.getId(); + public Long apply(HistoryTuple theInput) { + return (Long) theInput.getId(); } }); if (ids.isEmpty()) { @@ -221,7 +220,7 @@ public abstract class BaseFhirDao { CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); CriteriaQuery cq = builder.createQuery(ResourceHistoryTable.class); Root from = cq.from(ResourceHistoryTable.class); - cq.where(from.get("myPk").in(ids)); + cq.where(from.get("myId").in(ids)); cq.orderBy(builder.desc(from.get("myUpdated"))); TypedQuery q = myEntityManager.createQuery(cq); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDao.java index 70e6dd27167..6852b4dec12 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDao.java @@ -1,6 +1,6 @@ package ca.uhn.fhir.jpa.dao; -import static org.apache.commons.lang3.StringUtils.*; +import static org.apache.commons.lang3.StringUtils.isBlank; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +36,6 @@ import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.jpa.entity.BaseHasResource; import ca.uhn.fhir.jpa.entity.BaseTag; import ca.uhn.fhir.jpa.entity.ResourceHistoryTable; -import ca.uhn.fhir.jpa.entity.ResourceHistoryTablePk; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString; @@ -493,7 +492,7 @@ public class FhirResourceDao extends BaseFhirDao implements ArrayList retVal = new ArrayList(); String resourceType = getContext().getResourceDefinition(myResourceType).getName(); - TypedQuery q = myEntityManager.createQuery(ResourceHistoryTable.Q_GETALL, ResourceHistoryTable.class); + TypedQuery q = myEntityManager.createQuery("SELECT h FROM ResourceHistoryTable h WHERE h.myResourceId = :PID AND h.myResourceType = :RESTYPE ORDER BY h.myUpdated ASC", ResourceHistoryTable.class); q.setParameter("PID", theId.asLong()); q.setParameter("RESTYPE", resourceType); @@ -558,7 +557,11 @@ public class FhirResourceDao extends BaseFhirDao implements if (entity == null) { if (theId.hasUnqualifiedVersionId()) { - entity = myEntityManager.find(ResourceHistoryTable.class, new ResourceHistoryTablePk(myResourceName, theId.asLong(), theId.getUnqualifiedVersionIdAsLong())); + TypedQuery q = myEntityManager.createQuery("SELECT t from ResourceHistoryTable t WHERE t.myResourceId = :RID AND t.myResourceType = :RTYP AND t.myResourceVersion = :RVER", ResourceHistoryTable.class); + q.setParameter("RID", theId.asLong()); + q.setParameter("RTYP", myResourceName); + q.setParameter("RVER", theId.getUnqualifiedVersionIdAsLong()); + entity = q.getSingleResult(); } if (entity == null) { throw new ResourceNotFoundException(theId); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/HistoryTuple.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/HistoryTuple.java index d737a4cf687..3c7ea4b6dfe 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/HistoryTuple.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/HistoryTuple.java @@ -4,13 +4,13 @@ import java.util.Date; class HistoryTuple implements Comparable { - private Object myId; - private Class myTable; + private Long myId; + private boolean myIsHistory; private Date myUpdated; - public HistoryTuple(Class theTable, Date theUpdated, Object theId) { + public HistoryTuple(boolean theIsHistory, Date theUpdated, Long theId) { super(); - myTable = theTable; + myIsHistory = theIsHistory; myUpdated = theUpdated; myId = theId; } @@ -20,24 +20,24 @@ class HistoryTuple implements Comparable { return myUpdated.compareTo(theO.myUpdated); } - public Object getId() { + public Long getId() { return myId; } - public Class getTable() { - return myTable; + public boolean isHistory() { + return myIsHistory; } public Date getUpdated() { return myUpdated; } - public void setId(Object theId) { + public void setId(Long theId) { myId = theId; } - public void setTable(Class theTable) { - myTable = theTable; + public void setIsHistory(boolean theIsHistory) { + myIsHistory = theIsHistory; } public void setUpdated(Date theUpdated) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTable.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTable.java index 9491272f40c..643b5febf2d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTable.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTable.java @@ -6,11 +6,14 @@ import java.util.Collection; import javax.persistence.CascadeType; import javax.persistence.Column; -import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; +import javax.persistence.UniqueConstraint; import org.hibernate.annotations.Index; @@ -18,61 +21,30 @@ import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.server.Constants; @Entity -@Table(name = "HFJ_RES_VER", uniqueConstraints = {}) +@Table(name = "HFJ_RES_VER", uniqueConstraints = {@UniqueConstraint(name="IDX_RES_VER_ALL", columnNames = { "RES_ID", "RES_TYPE", "RES_VER" })}) @org.hibernate.annotations.Table(appliesTo="HFJ_RES_VER", indexes= {@Index(name="IDX_RES_VER_DATE", columnNames= {"RES_UPDATED"})}) public class ResourceHistoryTable extends BaseHasResource implements Serializable { - public static final String Q_GETALL = "SELECT h FROM ResourceHistoryTable h WHERE h.myPk.myId = :PID AND h.myPk.myResourceType = :RESTYPE ORDER BY h.myUpdated ASC"; - private static final long serialVersionUID = 1L; - @EmbeddedId - private ResourceHistoryTablePk myPk; - @Column(name="RES_TYPE",insertable=false, updatable=false) + @Id + @GeneratedValue(strategy=GenerationType.AUTO) + @Column(name="PID") + private Long myId; + + @Column(name = "RES_ID") + private Long myResourceId; + + @Column(name = "RES_TYPE", length = 30, nullable = false) private String myResourceType; - @Column(name="PID", insertable=false, updatable=false) - private Long myId; + @Column(name = "RES_VER", nullable = false) + private Long myResourceVersion; @OneToMany(mappedBy = "myResourceHistory", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true) private Collection myTags; - @Override - public IdDt getIdDt() { - return new IdDt(myPk.getResourceType() + '/' + myPk.getId() + '/' + Constants.PARAM_HISTORY + '/' + myPk.getVersion()); - } - - public ResourceHistoryTablePk getPk() { - return myPk; - } - - @SuppressWarnings("unchecked") - public String getResourceType() { - return myPk.getResourceType(); -// try { -// return (Class) Class.forName(Patient.class.getPackage().getName() + "." + myPk.getResourceType()); -// } catch (ClassNotFoundException e) { -// throw new InternalErrorException(e); -// } - } - - public Collection getTags() { - if (myTags == null) { - myTags = new ArrayList(); - } - return myTags; - } - - @Override - public long getVersion() { - return myPk.getVersion(); - } - - public void setPk(ResourceHistoryTablePk thePk) { - myPk = thePk; - } - public void addTag(ResourceHistoryTag theTag) { for (ResourceHistoryTag next : getTags()) { if (next.getTag().getTerm().equals(theTag)) { @@ -82,15 +54,6 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl getTags().add(theTag); } - public boolean hasTag(String theTerm, String theLabel, String theScheme) { - for (ResourceHistoryTag next : getTags()) { - if (next.getTag().getScheme().equals(theScheme) && next.getTag().getTerm().equals(theTerm)) { - return true; - } - } - return false; - } - public void addTag(ResourceTag theTag) { ResourceHistoryTag tag = new ResourceHistoryTag(this, theTag.getTag()); tag.setResourceType(theTag.getResourceType()); @@ -104,4 +67,51 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl return historyTag; } + @Override + public IdDt getIdDt() { + return new IdDt(getResourceType() + '/' + getResourceId() + '/' + Constants.PARAM_HISTORY + '/' + getVersion()); + } + + public Long getResourceId() { + return myResourceId; + } + + public String getResourceType() { + return myResourceType; + } + + + public Collection getTags() { + if (myTags == null) { + myTags = new ArrayList(); + } + return myTags; + } + + @Override + public long getVersion() { + return myResourceVersion; + } + + public boolean hasTag(String theTerm, String theLabel, String theScheme) { + for (ResourceHistoryTag next : getTags()) { + if (next.getTag().getScheme().equals(theScheme) && next.getTag().getTerm().equals(theTerm)) { + return true; + } + } + return false; + } + + public void setResourceId(Long theResourceId) { + myResourceId = theResourceId; + } + + public void setResourceType(String theResourceType) { + myResourceType=theResourceType; + } + + public void setVersion(long theVersion) { + myResourceVersion=theVersion; + } + } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTablePk.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTablePk.java deleted file mode 100644 index 70458a91c5b..00000000000 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTablePk.java +++ /dev/null @@ -1,94 +0,0 @@ -package ca.uhn.fhir.jpa.entity; - -import java.io.Serializable; - -import javax.persistence.Column; -import javax.persistence.Embeddable; - -@Embeddable -public class ResourceHistoryTablePk implements Serializable { - - private static final long serialVersionUID = 1L; - - @Column(name = "PID") - private Long myId; - - @Column(name = "RES_TYPE", length = 30, nullable = false) - private String myResourceType; - - @Column(name = "VERSION", nullable = false) - private Long myVersion; - - public ResourceHistoryTablePk() { - // nothing - } - - public ResourceHistoryTablePk(String theResourceType, Long theResourceId, Long theVersion) { - super(); - myResourceType = theResourceType; - myId = theResourceId; - myVersion = theVersion; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((myId == null) ? 0 : myId.hashCode()); - result = prime * result + ((myResourceType == null) ? 0 : myResourceType.hashCode()); - result = prime * result + ((myVersion == null) ? 0 : myVersion.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - ResourceHistoryTablePk other = (ResourceHistoryTablePk) obj; - if (myId == null) { - if (other.myId != null) - return false; - } else if (!myId.equals(other.myId)) - return false; - if (myResourceType == null) { - if (other.myResourceType != null) - return false; - } else if (!myResourceType.equals(other.myResourceType)) - return false; - if (myVersion == null) { - if (other.myVersion != null) - return false; - } else if (!myVersion.equals(other.myVersion)) - return false; - return true; - } - - public Long getId() { - return myId; - } - - public String getResourceType() { - return myResourceType; - } - - public Long getVersion() { - return myVersion; - } - - public void setId(Long theId) { - myId = theId; - } - - public void setResourceType(String theResourceType) { - myResourceType = theResourceType; - } - - public void setVersion(Long theVersion) { - myVersion = theVersion; - } - -} diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTag.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTag.java index 8d977adf72f..c8e1c719367 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTag.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTag.java @@ -8,7 +8,6 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; -import javax.persistence.JoinColumns; import javax.persistence.ManyToOne; import javax.persistence.Table; @@ -23,17 +22,13 @@ public class ResourceHistoryTag extends BaseTag implements Serializable { private Long myId; @ManyToOne() - @JoinColumns(value= { - @JoinColumn(name="RES_TYPE", referencedColumnName="RES_TYPE"), - @JoinColumn(name="PID", referencedColumnName="PID"), - @JoinColumn(name="VERSION", referencedColumnName="VERSION") - }/*, foreignKey=@ForeignKey(name="FK_HT_RT")*/) + @JoinColumn(name="RES_VER_PID", referencedColumnName="PID", nullable=false) private ResourceHistoryTable myResourceHistory; - @Column(name = "RES_TYPE", length = ResourceTable.RESTYPE_LEN,nullable=false, insertable=false, updatable=false) + @Column(name = "RES_TYPE", length = ResourceTable.RESTYPE_LEN, nullable=false) private String myResourceType; - @Column(name="PID", insertable=false,updatable=false) + @Column(name="RES_ID", nullable=false) private Long myResourceId; public String getResourceType() { @@ -63,6 +58,7 @@ public class ResourceHistoryTag extends BaseTag implements Serializable { public ResourceHistoryTag(ResourceHistoryTable theResourceHistoryTable, TagDefinition theTag) { myResourceHistory=theResourceHistoryTable; setTag(theTag); + setResourceId(theResourceHistoryTable.getResourceId()); } public ResourceHistoryTable getResourceHistory() { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java index 61f11ea7871..bd82bbe73fe 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java @@ -250,11 +250,9 @@ public class ResourceTable extends BaseHasResource implements Serializable { public ResourceHistoryTable toHistory(FhirContext theCtx) { ResourceHistoryTable retVal = new ResourceHistoryTable(); - ResourceHistoryTablePk pk = new ResourceHistoryTablePk(); - pk.setId(myId); - pk.setResourceType(myResourceType); - pk.setVersion(myVersion); - retVal.setPk(pk); + retVal.setResourceId(myId); + retVal.setResourceType(myResourceType); + retVal.setVersion(myVersion); retVal.setPublished(getPublished()); retVal.setUpdated(getUpdated());