Hello,
I am having performance problems with persisting a collection of
classes due (it seems to me) to the use of FetchMode.JOIN. I have
tried with FetchMode.SELECT but I have not managed to make it work, so
I am sending this email hoping to get some good hints towards a
solution to my problems.
I need to persist and consult instances of the class
LearnerModel. Each LearnerModel has a Map of Beliefs, with
BeliefDescriptors as keys. Each Belief contains a MassDistribution and
a List of Evidence, and each Evidence contains a MassDistribution and
other small fields.
I use an accessory class, called XlmSession to hide the details of the
persistence mechanism. When an XlmSession is open, with a given
learner identifier, then it retrieves the corresponding learner model
from the database, using FetchMode.JOIN. Then it produces individual
beliefs on request. The problem is that LearnerModels become quite big
and then FetchMode.JOIN becomes highly inefficient (even with second
level cache enabled). But if I try to use FetchMode.select, then only a
small fraction of the Map of Belief is retrieved.
See code extracts and mappings below for details. Please feel free to
send me any hints!
Hibernate version: 3.0.5
Database name and version: 10.0.2.1
Regards,
Rafael
package org.activemath.xlm.model;
public class XlmSession {
private int mode;
private LearnerModel lModel;
private String learnerId;
private Session session;
private Transaction transaction;
public static XlmSession getSession( String learnerId, int mode) {
XlmSession s = null;
try {
s = new XlmSession( learnerId, mode);
}
catch (XlmException e) {
return null;
}
return s;
}
public void release()
{
if (session == null) {
log.warn( "No Hibernate session to close.");
}
else {
if (transaction == null)
log.warn( "No transaction to release!");
else {
try {
transaction.commit();
}
catch (HibernateException e) {
log.error( "..." , e);
transaction.rollback();
}
finally {
session.close();
transaction = null;
session = null;
}
}
}
}
private XlmSession( String learnerId, int mode)
throws XlmException
{
this.learnerId = learnerId;
this.mode = mode;
session = HibernateHelper.getInstance().getXlmModelSession();
if (session == null) {
throw new XlmException( "...");
}
transaction = null;
XlmException exception = null;
try {
transaction = session.beginTransaction();
Criteria criteria = session.createCriteria( LearnerModel.class)
// The following line is the one that produces a full
// load of the learner model. It is included here
// because I have not been able so far to make
// select/lazy fetching to work. Use of Hibernate
// second-level cache makes this line a bit less harmful.
.setFetchMode( "beliefs", FetchMode.JOIN)
// This is the line that does not work.
// .setFetchMode( "beliefs", FetchMode.SELECT)
.add( Restrictions.eq( "learnerId", learnerId));
lModel = (LearnerModel) criteria.uniqueResult();
if (lModel == null)
throw new XlmException( "...");
}
catch (Exception e) {
if (transaction != null)
transaction.rollback();
exception = new XlmException( e.getMessage());
}
finally {
if (exception != null) {
session.close();
throw exception;
}
}
}
public LearnerModel getModel() {
// TODO Auto-generated method stub
return lModel;
}
public Belief getBelief( BeliefDescriptor descriptor) {
return lModel.getBelief( descriptor);
}
public synchronized BeliefDescriptor persistBeliefDescriptor(
BeliefDescriptor desc)
{
NaturalIdentifier natId = descriptorAsIdentifier( desc);
Criteria criteria = session.createCriteria( BeliefDescriptor.class);
criteria.add( natId);
BeliefDescriptor pDesc = null;
Transaction t = null;
try {
t = session.beginTransaction();
pDesc = (BeliefDescriptor) criteria.uniqueResult();
t.commit();
}
catch (HibernateException e) {
if (t != null)
t.rollback();
return null;
}
if (pDesc != null) {
return pDesc;
}
else {
t = null;
try {
t = session.beginTransaction();
session.save( desc);
t.commit();
}
catch (HibernateException e) {
if (t != null)
t.rollback();
desc = null;
}
return desc;
}
}
private static NaturalIdentifier descriptorAsIdentifier(
BeliefDescriptor desc)
{
NaturalIdentifier id = new NaturalIdentifier().set( "metacogId",
desc.metacogId).set( "affectId", desc.affectId).set(
"motivationId", desc.motivationId).set( "competencyId",
desc.competencyId).set( "capeId", desc.capeId).set( "domainId",
desc.domainId);
return id;
}
...
}
CLASSES
======================================================================
package org.activemath.xlm.model;
...
public class LearnerModel {
private long id;
Map beliefs;
LearnerModel() {
learnerId = null;
beliefs = null;
}
LearnerModel(String learnerId) {
this.learnerId = learnerId;
this.beliefs = new Hashtable();
}
String getLearnerId() {
return learnerId;
}
public long getId() {
return id;
}
void setLearnerId(String learnerId) {
this.learnerId = learnerId;
}
public Belief getBelief(BeliefDescriptor beliefId) {
Belief b = (Belief) beliefs.get(beliefId);
return (b != null) ? b : new Belief();
}
...
}
======================================================================
package org.activemath.xlm.model;
public class Belief {
LearnerModel lModel;
BeliefDescriptor descriptor;
private List evidence;
MassDistribution massDist;
public Belief() {
this.massDist = new MassDistribution();
this.evidence = new ArrayList();
}
public Belief(LearnerModel model, BeliefDescriptor desc) {
this();
this.lModel = model;
this.descriptor = desc;
}
...
}
======================================================================
package org.activemath.xlm.model;
public class MassDistribution {
private double[] massDist;
...
}
======================================================================
package org.activemath.xlm.model;
public class Evidence {
private long eventId;
private int type;
private int action;
private double discount;
private MassDistribution mass;
...
protected Evidence()
{
eventId = -1;
type = DIRECT;
action = ADD;
discount = DEFAULT_DISCOUNT;
mass = new MassDistribution();
}
...
}
======================================================================
package org.activemath.xlm.model;
public class BeliefDescriptor {
String metacogId;
String motivationId;
String affectId;
String competencyId;
String capeId;
String domainId;
protected static final String UNSET = "_UNSET";
protected static final String PRINTABLE_UNSET = "_";
private long id;
public BeliefDescriptor ()
{
metacogId = UNSET;
affectId = UNSET;
motivationId = UNSET;
competencyId = UNSET;
capeId = UNSET;
domainId = UNSET;
}
/**
* Produces a deep copy of the given belief descriptor.
*
* @return An instance that is a deep copy of the given instance.
*/
public BeliefDescriptor (BeliefDescriptor model)
{
metacogId = model.metacogId;
affectId = model.affectId;
motivationId = model.motivationId;
competencyId = model.competencyId;
capeId = model.capeId;
domainId = model.domainId;
}
...
}
MAPPINGS
======================================================================
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"conf/hibernate/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.activemath.xlm.model">
<class name="LearnerModel" table="LModel">
<cache usage="read-write"/>
<id name="id" access="field" type="long">
<generator class="native" />
</id>
<natural-id>
<property name="learnerId" access="field"/>
</natural-id>
<map name="beliefs" inverse="true" cascade="all-delete-orphan">
<cache usage="read-write"/>
<key column="lModelId" on-delete="cascade"/>
<map-key-many-to-many class="BeliefDescriptor"
column="descriptorId" />
<one-to-many class="Belief"/>
</map>
</class>
</hibernate-mapping>
======================================================================
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"conf/hibernate/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-access="field"
package="org.activemath.xlm.model">
<class name="Belief" table="Belief" >
<cache usage="read-write" />
<id type="long">
<generator class="native" />
</id>
<natural-id>
<many-to-one name="lModel" access="field" class="LearnerModel"
column="lModelId" not-null="true"/>
<many-to-one name="descriptor" access="field"
class="BeliefDescriptor" column="descriptorId" not-null="true"/>
</natural-id>
<property name="unresolved" />
<component class="MassDistribution" name="massDist">
<primitive-array name="massDist" table="MassDist">
<key column="Belief_id"/>
<list-index column="lSetOrd"/>
<element column="bpa" type="double" />
</primitive-array>
</component>
<list access="field" name="evidence" cascade="all,delete-orphan">
<cache usage="read-write"/>
<key column="Belief_id" not-null="true"/>
<list-index column="n" />
<one-to-many class="Evidence"/>
</list>
</class>
</hibernate-mapping>
======================================================================
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"conf/hibernate/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.activemath.xlm.model">
<class name="Evidence" table="Evidence">
<cache usage="read-write" />
<id type="long">
<generator class="native"/>
</id>
<property name="eventId"/>
<property name="type"/>
<property name="action"/>
<property name="discount"/>
<component class="MassDistribution" name="mass">
<primitive-array name="massDist" access="field" table="EventInterp">
<key not-null="true" column="Evidence_id"/>
<list-index column="lSetOrd"/>
<element column="bpa" type="double"/>
</primitive-array>
</component>
</class>
</hibernate-mapping>
======================================================================
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"conf/hibernate/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.activemath.xlm.model.BeliefDescriptor" lazy="false"
table="BDesc">
<cache usage="read-write" />
<id name="id" access="field" type="long">
<generator class="native" />
</id>
<natural-id>
<property name="metacogId" access="field">
<column name="metacogId" sql-type="varchar(80)"/>
</property>
<property name="motivationId" access="field">
<column name="motivationId" sql-type="varchar(80)"/>
</property>
<property name="affectId" access="field">
<column name="affectId" sql-type="varchar(80)"/>
</property>
<property name="competencyId" access="field">
<column name="competencyId" sql-type="varchar(80)"/>
</property>
<property name="capeId" access="field">
<column name="capeId" sql-type="varchar(80)"/>
</property>
<property name="domainId" access="field">
<column name="domainId" sql-type="varchar(80)"/>
</property>
</natural-id>
</class>
</hibernate-mapping>
|