-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Reverse Engineering a timeseries database
PostPosted: Mon Jun 16, 2008 10:49 pm 
Newbie

Joined: Wed Jun 04, 2008 9:46 pm
Posts: 5
Hi,

I am working with a legacy database of time series and am trying to develop a java application on top of it. Since I am new to hibernate, I am having trouble figuring out the mapping of the time series. A simplified version of the tables of interest are as shown below (click on the thumbnail for a larger view):

Image


We have locations where we are taking measurements several times a day with different types of instruments. The table locations has information about the location where the measurement is being made and a primary key that is a long integer. There are different types of instruments that are used to make the measurements. This information is stored in a table instruments which has a primary key that is a long integer. Finally we take measurements at a specific time in the morning and in the evening and also record the high and the low through the course of the day. The information about the measurements is stored in a table measurements that has a primary key that is a long integer. The time series information is stored in a table time_series. This table has a composite primary key that consists of three foreign keys, location_id, instrument_id and measurement_id, and the date of the measurement. I have been able to create classes for each of the tables: locations, instruments and measurements. This was very easy and I was happy about how straightforward it was to do with hibernate. Creating a class for the last table is beyond my limited skills in hibernate. Ideally we would have a class has a composite key consisting of location_id, instrument_id and measurement_id (the classes that represent the rows in the database) and a map consisting (date, value) pairs: i.e.

Public class TimeSeries{

Private Location location;
Private Instrument instrument;
Private Measurment measurement;
Private Map<date,double> timeseries = new HashMap<date,double>();

… setters and getters, etc;

}

I would appreciate suggestions on how to do this. The straightforward approach that I tried, gave me an error Foreign key <> must have same number of columns as the referenced primary key.

Thanks in advance for any help and suggestions!


Top
 Profile  
 
 Post subject: Reverse Engineering a timeseries database cont
PostPosted: Wed Jun 18, 2008 7:11 am 
Newbie

Joined: Wed Jun 04, 2008 9:46 pm
Posts: 5
I thought that it might be helpful to others (and myself) if I detailed my thoughts and learning process as I work through the issues.

The first step I took was to reverse engineer the database using hibernate. This gives me several classes. They are as follows:

Instruments.java: This is the class that identifies which instruments are doing the measuring

Code:
package org.hibernate.timeseries;
// Generated Jun 17, 2008 11:33:48 PM by Hibernate Tools 3.2.1.GA


import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/**
* Instruments generated by hbm2java
*/
@Entity
@Table(name="instruments"
    ,schema="weather"
)
public class Instruments  implements java.io.Serializable {


     /**
    *
    */
   private static final long serialVersionUID = -8742383364804218579L;
   private int id;
     private String description;
     private Set<Timeseries> timeseriesesForLocationId = new HashSet<Timeseries>(0);
     private Set<Timeseries> timeseriesesForInstrumentId = new HashSet<Timeseries>(0);

    public Instruments() {
    }

   
    public Instruments(int id, String description) {
        this.id = id;
        this.description = description;
    }
    public Instruments(int id, String description, Set<Timeseries> timeseriesesForLocationId, Set<Timeseries> timeseriesesForInstrumentId) {
       this.id = id;
       this.description = description;
       this.timeseriesesForLocationId = timeseriesesForLocationId;
       this.timeseriesesForInstrumentId = timeseriesesForInstrumentId;
    }
   
     @Id
   
    @Column(name="id", unique=true, nullable=false)
    public int getId() {
        return this.id;
    }
   
    public void setId(int id) {
        this.id = id;
    }
   
    @Column(name="description", nullable=false, length=120)
    public String getDescription() {
        return this.description;
    }
   
    public void setDescription(String description) {
        this.description = description;
    }
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="instrumentsByLocationId")
    public Set<Timeseries> getTimeseriesesForLocationId() {
        return this.timeseriesesForLocationId;
    }
   
    public void setTimeseriesesForLocationId(Set<Timeseries> timeseriesesForLocationId) {
        this.timeseriesesForLocationId = timeseriesesForLocationId;
    }
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="instrumentsByInstrumentId")
    public Set<Timeseries> getTimeseriesesForInstrumentId() {
        return this.timeseriesesForInstrumentId;
    }
   
    public void setTimeseriesesForInstrumentId(Set<Timeseries> timeseriesesForInstrumentId) {
        this.timeseriesesForInstrumentId = timeseriesesForInstrumentId;
    }


}

Locations.java: This is the class that contains information about the locations where the measurements are being done

Code:
package org.hibernate.timeseries;
// Generated Jun 17, 2008 11:33:48 PM by Hibernate Tools 3.2.1.GA


import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

/**
* Locations generated by hbm2java
*/
@Entity
@Table(name="locations"
    ,schema="weather"
)
public class Locations  implements java.io.Serializable {


     private int id;
     private String description;

    public Locations() {
    }

    public Locations(int id, String description) {
       this.id = id;
       this.description = description;
    }
   
     @Id
   
    @Column(name="id", unique=true, nullable=false)
    public int getId() {
        return this.id;
    }
   
    public void setId(int id) {
        this.id = id;
    }
   
    @Column(name="description", nullable=false, length=120)
    public String getDescription() {
        return this.description;
    }
   
    public void setDescription(String description) {
        this.description = description;
    }


}


Measurements.java: This is the class that contains information about the time of day/type of measurement that is being done

Code:
package org.hibernate.timeseries;
// Generated Jun 17, 2008 11:33:48 PM by Hibernate Tools 3.2.1.GA


import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/**
* Measurements generated by hbm2java
*/
@Entity
@Table(name="measurements"
    ,schema="weather"
)
public class Measurements  implements java.io.Serializable {


     private int id;
     private String description;
     private Set<Timeseries> timeserieses = new HashSet<Timeseries>(0);

    public Measurements() {
    }

   
    public Measurements(int id, String description) {
        this.id = id;
        this.description = description;
    }
    public Measurements(int id, String description, Set<Timeseries> timeserieses) {
       this.id = id;
       this.description = description;
       this.timeserieses = timeserieses;
    }
   
     @Id
   
    @Column(name="id", unique=true, nullable=false)
    public int getId() {
        return this.id;
    }
   
    public void setId(int id) {
        this.id = id;
    }
   
    @Column(name="description", nullable=false, length=120)
    public String getDescription() {
        return this.description;
    }
   
    public void setDescription(String description) {
        this.description = description;
    }
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="measurements")
    public Set<Timeseries> getTimeserieses() {
        return this.timeserieses;
    }
   
    public void setTimeserieses(Set<Timeseries> timeserieses) {
        this.timeserieses = timeserieses;
    }

}


Finally there are the classes that are associated with our actual timeseries table. It is a link table. Two classes are generated. One is called TimeseriesID.java which is the class that wraps the composite primary key of the table

Code:
package org.hibernate.timeseries;
// Generated Jun 17, 2008 11:33:48 PM by Hibernate Tools 3.2.1.GA


import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Embeddable;

/**
* TimeseriesId generated by hbm2java
*/
@Embeddable
public class TimeseriesId  implements java.io.Serializable {


     /**
    *
    */
   private static final long serialVersionUID = 4880400296435235114L;
   private int locationId;
     private int measurementId;
     private int instrumentId;
     private Date datetime;

    public TimeseriesId() {
    }

    public TimeseriesId(int locationId, int measurementId, int instrumentId, Date datetime) {
       this.locationId = locationId;
       this.measurementId = measurementId;
       this.instrumentId = instrumentId;
       this.datetime = datetime;
    }
   

    @Column(name="location_id", nullable=false)
    public int getLocationId() {
        return this.locationId;
    }
   
    public void setLocationId(int locationId) {
        this.locationId = locationId;
    }

    @Column(name="measurement_id", nullable=false)
    public int getMeasurementId() {
        return this.measurementId;
    }
   
    public void setMeasurementId(int measurementId) {
        this.measurementId = measurementId;
    }

    @Column(name="instrument_id", nullable=false)
    public int getInstrumentId() {
        return this.instrumentId;
    }
   
    public void setInstrumentId(int instrumentId) {
        this.instrumentId = instrumentId;
    }

    @Column(name="datetime", nullable=false, length=13)
    public Date getDatetime() {
        return this.datetime;
    }
   
    public void setDatetime(Date datetime) {
        this.datetime = datetime;
    }


   public boolean equals(Object other) {
         if ( (this == other ) ) return true;
       if ( (other == null ) ) return false;
       if ( !(other instanceof TimeseriesId) ) return false;
       TimeseriesId castOther = ( TimeseriesId ) other;
         
       return (this.getLocationId()==castOther.getLocationId())
&& (this.getMeasurementId()==castOther.getMeasurementId())
&& (this.getInstrumentId()==castOther.getInstrumentId())
&& ( (this.getDatetime()==castOther.getDatetime()) || ( this.getDatetime()!=null && castOther.getDatetime()!=null && this.getDatetime().equals(castOther.getDatetime()) ) );
   }
   
   public int hashCode() {
         int result = 17;
         
         result = 37 * result + this.getLocationId();
         result = 37 * result + this.getMeasurementId();
         result = 37 * result + this.getInstrumentId();
         result = 37 * result + ( getDatetime() == null ? 0 : this.getDatetime().hashCode() );
         return result;
   }   


}


and Timeseries.java which is the class that represents an row of the table

Code:
package org.hibernate.timeseries;
// Generated Jun 17, 2008 11:33:48 PM by Hibernate Tools 3.2.1.GA


import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Embeddable;

/**
* TimeseriesId generated by hbm2java
*/
@Embeddable
public class TimeseriesId  implements java.io.Serializable {


     /**
    *
    */
   private static final long serialVersionUID = 4880400296435235114L;
   private int locationId;
     private int measurementId;
     private int instrumentId;
     private Date datetime;

    public TimeseriesId() {
    }

    public TimeseriesId(int locationId, int measurementId, int instrumentId, Date datetime) {
       this.locationId = locationId;
       this.measurementId = measurementId;
       this.instrumentId = instrumentId;
       this.datetime = datetime;
    }
   

    @Column(name="location_id", nullable=false)
    public int getLocationId() {
        return this.locationId;
    }
   
    public void setLocationId(int locationId) {
        this.locationId = locationId;
    }

    @Column(name="measurement_id", nullable=false)
    public int getMeasurementId() {
        return this.measurementId;
    }
   
    public void setMeasurementId(int measurementId) {
        this.measurementId = measurementId;
    }

    @Column(name="instrument_id", nullable=false)
    public int getInstrumentId() {
        return this.instrumentId;
    }
   
    public void setInstrumentId(int instrumentId) {
        this.instrumentId = instrumentId;
    }

    @Column(name="datetime", nullable=false, length=13)
    public Date getDatetime() {
        return this.datetime;
    }
   
    public void setDatetime(Date datetime) {
        this.datetime = datetime;
    }


   public boolean equals(Object other) {
         if ( (this == other ) ) return true;
       if ( (other == null ) ) return false;
       if ( !(other instanceof TimeseriesId) ) return false;
       TimeseriesId castOther = ( TimeseriesId ) other;
         
       return (this.getLocationId()==castOther.getLocationId())
&& (this.getMeasurementId()==castOther.getMeasurementId())
&& (this.getInstrumentId()==castOther.getInstrumentId())
&& ( (this.getDatetime()==castOther.getDatetime()) || ( this.getDatetime()!=null && castOther.getDatetime()!=null && this.getDatetime().equals(castOther.getDatetime()) ) );
   }
   
   public int hashCode() {
         int result = 17;
         
         result = 37 * result + this.getLocationId();
         result = 37 * result + this.getMeasurementId();
         result = 37 * result + this.getInstrumentId();
         result = 37 * result + ( getDatetime() == null ? 0 : this.getDatetime().hashCode() );
         return result;
   }   


}


I am using annotations since as I am learning hibernate it is easier for me to have both the code and the hibernate annotations before at once instead of moving between the java code and the hibernate.hbm.xml files.

My reading has lead to me suspect that Timeseries.java and TimeseriesId.java are going to be a part of any solution I find, probably with the TimeseriesId being moved inside the Timeseries class which will be renamed TimeseriesElement.java or something similar.

Two strategies for getting the class I want appear to be: 1. Create a Timeseries.java which will contain a map of TimeseriesElement keyed by date; 2. Turn the class Instrument into my de facto timeseries class. So I will spend some time rereading the hibernate docs to see if I can do either of these or/and if they meet my needs.

we'll see where this takes me.


Top
 Profile  
 
 Post subject: Reverse Engineering a timeseries database
PostPosted: Sun Jul 20, 2008 4:22 pm 
Newbie

Joined: Wed Jun 04, 2008 9:46 pm
Posts: 5
I have been continuing my effort to understand how to map the legacy structure using hibernate or to develop an alternative approach that would work well with hibernate. To that end, I have proposed restructuring the database to have the following structure:
Image

This improves the normalization of the database and will also save space.

I would appreciate any comments or criticisms of this structure. In particular are there any performance issues that I should worry about?

Thanks in advance.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.