4

Actually i have a basex collection with 15000 registries, i'm implementing a jsf and basex aplication, but i got a issue with the performance of the queries, actually i'm using JAXB to convert the xml into objects in java, but is very slow, this is how i do the basex queries:

public class AssetDao implements Dao<Asset>{
public static AssetDao instance;
private String db ="deterioro";
private String assetsModule = "import module namespace assets='http://creativosdigitales.co/cartera/assets' at 'C:/Users/santiago umaña/Google Drive/Deterioro/xquery/assets.xqm';";
private String simulationsModule = "import module namespace simulations='http://creativosdigitales.co/cartera/simulations' at 'C:/Users/santiago umaña/Google Drive/Deterioro/xquery/simulations.xqm';";

public static AssetDao getInstance() {
    if(instance == null) {
        instance = new AssetDao();
    }
    return instance;
}

@Override
public List<Asset> get() throws IOException, JAXBException {
    List<Asset> results = new ArrayList<Asset>();
    try(BaseXClient session = new BaseXClient("localhost", 1984, "admin", "admin")){
        session.execute("open "+db);
        final String xquery = "for $data in subsequence(//asset, 1, 20) return <asset> {$data/assetid} {$data/payment} {$data/pendingpayments} <balance>{ format-number($data/balance, \"#.00\") }</balance> <npv>{ format-number(sum(//simulation[assetid=$data/assetid]/payment/npv), \"#.00\") }</npv> <difference>{ format-number($data/balance - sum(//simulation[assetid=$data/assetid]/payment/npv), \"#.00\") }</difference> </asset>";
        JAXBContext context = JAXBContext.newInstance(Asset.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        Query query = session.query(xquery);
        while(query.more()) {
            results.add((Asset) unmarshaller.unmarshal(new StringReader(query.next())));
        }
        return results;
    }
}

//custom methods
public List<ExtraField> getExtraFields(String assetId) throws IOException, JAXBException {
    List<ExtraField> extraFields = new ArrayList<ExtraField>();
    try(BaseXClient session = new BaseXClient("localhost", 1984, "admin", "admin")){
        final String xquery = assetsModule
                + "let $db := collection('"+db+"')"
                + "let $asset := assets:asset-info($db, '"+assetId+"')"
                + "return assets:extra-fields($asset)";
        JAXBContext context = JAXBContext.newInstance(ExtraField.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        Query query = session.query(xquery);
        System.out.println(query.toString());
        while(query.more()) {
            extraFields.add((ExtraField) unmarshaller.unmarshal(new StringReader(query.next())));
        }
        return extraFields;
    }
}

public List<Simulation> getSimulation(String assetId) throws IOException, JAXBException {
    List<Simulation> simulations = new ArrayList<Simulation>();
    try(BaseXClient session = new BaseXClient("localhost", 1984, "admin", "admin")){
        final String xquery = assetsModule
                + simulationsModule
                + "let $db := collection('"+db+"')"
                + "let $asset := assets:asset-info($db, '"+assetId+"')"
                + "return simulations:simulation-xml($asset)";
        JAXBContext context = JAXBContext.newInstance(Simulation.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        Query query = session.query(xquery);
        System.out.println(query.toString());
        while(query.more()) {
            simulations.add((Simulation) unmarshaller.unmarshal(new StringReader(query.next())));
        }
        return simulations;
    }
}

this is my xquery module:

module namespace assets='http://creativosdigitales.co/cartera/assets';

declare function assets:asset-list() 
{
  for $data in subsequence(//asset, 1, 100) 
  return 
  <asset> 
    {$data/assetid} 
    {$data/payment} 
    {$data/pendingpayments} 
    <balance>{ format-number($data/balance, "#.00") }</balance> 
    <npv>{ format-number(sum(//simulation[assetid=$data/assetid]/payment/npv), "#.00") }</npv> 
    <difference>{ format-number($data/balance - sum(//simulation[assetid=$data/assetid]/payment/npv), "#.00") }</difference> 
   </asset>
};

declare function assets:asset-info($collection, $assetid)
{
  <asset>
  { $collection/*/asset[assetid=$assetid]/*,
    $collection//simulation[assetid=$assetid],
    $collection//punishment[assetid=$assetid] }
  </asset>
};

declare function assets:extra-fields($info)
{
  let $standard := ('assetid','customerid','customername','amount','term','balance','default','rate','payment','pendingpayments', 'paidpayments', 'extrapayments', 'totalnpv', 'punishment', 'expectednpv', 'simulation', 'policy')
  for $x in $info/*[name() != $standard ]
  return
    <extrafield>
      <name>{ $x/name() }</name>
      <text>{ $x/text() }</text>
    </extrafield>
};

Actually loading 100 items takes some 2 or 3 mins, loading 20 items takes 20 secs, how do I get a better performance to get the items and parse into java objects?

pd: this is my java object:

@ManagedBean
@XmlRootElement(name="asset")
@XmlType(propOrder = {"assetid", "payment", "pendingpayments", "balance", "npv", "difference"})
public class Asset {
    private String assetid;
    private String payment;
    private String pendingpayments;
    private String balance;
    //net present value
    private String npv;
    //difference between balance and npv
    private String difference; 

    public Asset() {
        // TODO Auto-generated constructor stub
    }

    @XmlElement(name="assetid")
    public String getAssetid() {
        return assetid;
    }

    public void setAssetid(String assetid) {
        this.assetid = assetid;
    }

    @XmlElement(name="payment")
    public String getPayment() {
        return payment;
    }

    public void setPayment(String payment) {
        this.payment = payment;
    }

    @XmlElement(name="pendingpayments")
    public String getPendingpayments() {
        return pendingpayments;
    }

    public void setPendingpayments(String pendingpayments) {
        this.pendingpayments = pendingpayments;
    }

    @XmlElement(name="balance")
    public String getBalance() {
        return balance;
    }

    public void setBalance(String balance) {
        this.balance = balance;
    }

    @XmlElement(name="npv")
    public String getNpv() {
        return npv;
    }

    public void setNpv(String npv) {
        this.npv = npv;
    }

    @XmlElement(name="difference")
    public String getDifference() {
        return difference;
    }

    public void setDifference(String difference) {
        this.difference = difference;
    }
}
  • 3
    Did you do any measurements where exactly this time is spent? JAXB is known for being not very performant, so you might want to look into that. Your query is certainly not optimal performance-wise (e.g.: Never use `//`if performance is important for you), but 2 to 3 minutes for the scenario you describes sounds very slow to me. Did you try running the queries e.g. using the BaseX GUI, this way you can see were the time is actually spent (and how long BaseX in general needs) – dirkk Aug 28 '17 at 19:27
  • In your `assets:extra-fields()` function, you may want to adjust the predicate from `for $x in $info/*[name() != $standard ]` to `for $x in $info/*[not(name() = $standard) ]`. Inequalities for sets vs single values behaves different than what most people initially assume. Not necessarily performance related, but likely a bug. – Mads Hansen Aug 02 '21 at 12:20

0 Answers0