package org.wikibrain.core.dao.sql; import com.typesafe.config.Config; import org.jooq.*; import org.wikibrain.conf.Configuration; import org.wikibrain.conf.ConfigurationException; import org.wikibrain.conf.Configurator; import org.wikibrain.core.dao.DaoException; import org.wikibrain.core.dao.DaoFilter; import org.wikibrain.core.dao.LocalLinkDao; import org.wikibrain.core.jooq.Tables; import org.wikibrain.core.lang.Language; import org.wikibrain.core.lang.LocalId; import org.wikibrain.core.model.LocalLink; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; public class LocalLinkSqlDao extends AbstractSqlDao<LocalLink> implements LocalLinkDao { public LocalLinkSqlDao(WpDataSource dataSource) throws DaoException { super(dataSource, INSERT_FIELDS, "/db/local-link"); } private static final TableField [] INSERT_FIELDS = new TableField[] { Tables.LOCAL_LINK.LANG_ID, Tables.LOCAL_LINK.ANCHOR_TEXT, Tables.LOCAL_LINK.SOURCE_ID, Tables.LOCAL_LINK.DEST_ID, Tables.LOCAL_LINK.LOCATION, Tables.LOCAL_LINK.IS_PARSEABLE, Tables.LOCAL_LINK.LOCATION_TYPE, }; @Override public void save(LocalLink localLink) throws DaoException { insert( localLink.getLanguage().getId(), localLink.getAnchorText(), localLink.getSourceId(), localLink.getDestId(), localLink.getLocation(), localLink.isParseable(), localLink.getLocType().ordinal() ); } @Override public Iterable<LocalLink> get(DaoFilter daoFilter) throws DaoException { DSLContext context = getJooq(); try { Collection<Condition> conditions = new ArrayList<Condition>(); if (daoFilter.getLangIds() != null) { conditions.add(Tables.LOCAL_LINK.LANG_ID.in(daoFilter.getLangIds())); } if (daoFilter.getLocTypes() != null) { conditions.add(Tables.LOCAL_LINK.LOCATION_TYPE.in(daoFilter.getLocTypes())); } if (daoFilter.getSourceIds() != null) { conditions.add(Tables.LOCAL_LINK.SOURCE_ID.in(daoFilter.getSourceIds())); } if (daoFilter.getDestIds() != null) { conditions.add(Tables.LOCAL_LINK.DEST_ID.in(daoFilter.getDestIds())); } if (daoFilter.isParseable() != null) { conditions.add(Tables.LOCAL_LINK.IS_PARSEABLE.in(daoFilter.isParseable())); } if (daoFilter.getHasDest() != null) { conditions.add(Tables.LOCAL_LINK.DEST_ID.ne(-1)); } Cursor<Record> result = context.select(). from(Tables.LOCAL_LINK). where(conditions). limit(daoFilter.getLimitOrInfinity()). fetchLazy(getFetchSize()); return new SimpleSqlDaoIterable<LocalLink>(result, context) { @Override public LocalLink transform(Record r) { return buildLocalLink(r, true); } }; } catch (RuntimeException e) { freeJooq(context); throw e; } } @Override public int getCount(DaoFilter daoFilter) throws DaoException{ DSLContext context = getJooq(); try { Collection<Condition> conditions = new ArrayList<Condition>(); if (daoFilter.getLangIds() != null) { conditions.add(Tables.LOCAL_LINK.LANG_ID.in(daoFilter.getLangIds())); } if (daoFilter.getLocTypes() != null) { conditions.add(Tables.LOCAL_LINK.LOCATION_TYPE.in(daoFilter.getLocTypes())); } if (daoFilter.getSourceIds() != null) { conditions.add(Tables.LOCAL_LINK.SOURCE_ID.in(daoFilter.getSourceIds())); } if (daoFilter.getDestIds() != null) { conditions.add(Tables.LOCAL_LINK.DEST_ID.in(daoFilter.getDestIds())); } if (daoFilter.isParseable() != null) { conditions.add(Tables.LOCAL_LINK.IS_PARSEABLE.in(daoFilter.isParseable())); } if (daoFilter.getHasDest() != null) { conditions.add(Tables.LOCAL_LINK.DEST_ID.ne(-1)); } return context.selectDistinct(Tables.LOCAL_LINK.SOURCE_ID,Tables.LOCAL_LINK.DEST_ID). from(Tables.LOCAL_LINK). where(conditions). fetchCount(); } finally { freeJooq(context); } } @Override public LocalLink getLink(Language language, int sourceId, int destId) throws DaoException { DSLContext context = getJooq(); try { Result<Record> result = context.select(). from(Tables.LOCAL_LINK). where(Tables.LOCAL_LINK.LANG_ID.eq(language.getId())). and(Tables.LOCAL_LINK.SOURCE_ID.eq(sourceId)). and(Tables.LOCAL_LINK.DEST_ID.eq(destId)). fetch(); //Work-around to avoid pages that have multiple links to the same page Record record; if (result.isEmpty()){ record = null; } else { record = result.get(0); } return buildLocalLink(record, true); } catch (RuntimeException e) { freeJooq(context); throw e; } } @Override public double getPageRank(Language language, int pageId) { throw new UnsupportedOperationException(); } @Override public double getPageRank(LocalId localId) { throw new UnsupportedOperationException(); } @Override public Iterable<LocalLink> getLinks(Language language, int localId, boolean outlinks, boolean isParseable, LocalLink.LocationType locationType) throws DaoException{ DSLContext context = getJooq(); try { TableField idField; if (outlinks){ idField = Tables.LOCAL_LINK.SOURCE_ID; } else { idField = Tables.LOCAL_LINK.DEST_ID; } Cursor<Record> result = context.select() .from(Tables.LOCAL_LINK) .where(Tables.LOCAL_LINK.LANG_ID.equal(language.getId())) .and(idField.equal(localId)) .and(Tables.LOCAL_LINK.IS_PARSEABLE.equal(isParseable)) .and(Tables.LOCAL_LINK.LOCATION_TYPE.equal((short) locationType.ordinal())) .fetchLazy(getFetchSize()); return buildLocalLinks(result, outlinks, context); } catch (RuntimeException e) { freeJooq(context); throw e; } } // private static final AtomicLong counter = new AtomicLong(); // private static final AtomicLong timer = new AtomicLong(); @Override public Iterable<LocalLink> getLinks(Language language, int localId, boolean outlinks) throws DaoException{ // if (counter.incrementAndGet() % 1000 == 0) { // double mean = 1.0 * timer.get() / counter.get(); // System.out.println("counter is " + counter.get() + ", mean millis is " + mean); // } DSLContext context = getJooq(); // long start = System.currentTimeMillis(); try { TableField idField; if (outlinks){ idField = Tables.LOCAL_LINK.SOURCE_ID; } else { idField = Tables.LOCAL_LINK.DEST_ID; } Cursor<Record> result = context.select() .from(Tables.LOCAL_LINK) .where(Tables.LOCAL_LINK.LANG_ID.equal(language.getId())) .and(idField.equal(localId)) .fetchLazy(getFetchSize()); // long end = System.currentTimeMillis(); // timer.addAndGet(end - start); return buildLocalLinks(result, outlinks, context); } catch (RuntimeException e) { freeJooq(context); throw e; } } private Iterable<LocalLink> buildLocalLinks(Cursor<Record> result, final boolean outlink, DSLContext context){ return new SimpleSqlDaoIterable<LocalLink>(result, context) { @Override public LocalLink transform(Record r) { return buildLocalLink(r, outlink); } }; } private LocalLink buildLocalLink(Record record, boolean outlink){ if (record == null){ return null; } return new LocalLink( Language.getById(record.getValue(Tables.LOCAL_LINK.LANG_ID)), record.getValue(Tables.LOCAL_LINK.ANCHOR_TEXT), record.getValue(Tables.LOCAL_LINK.SOURCE_ID), record.getValue(Tables.LOCAL_LINK.DEST_ID), outlink, record.getValue(Tables.LOCAL_LINK.LOCATION), record.getValue(Tables.LOCAL_LINK.IS_PARSEABLE), LocalLink.LocationType.values()[record.getValue(Tables.LOCAL_LINK.LOCATION_TYPE)] ); } public static class Provider extends org.wikibrain.conf.Provider<LocalLinkDao> { public Provider(Configurator configurator, Configuration config) throws ConfigurationException { super(configurator, config); } @Override public Class<LocalLinkDao> getType() { return LocalLinkDao.class; } @Override public String getPath() { return "dao.localLink"; } @Override public LocalLinkSqlDao get(String name, Config config, Map<String, String> runtimeParams) throws ConfigurationException { if (!config.getString("type").equals("sql")) { return null; } try { return new LocalLinkSqlDao( getConfigurator().get( WpDataSource.class, config.getString("dataSource")) ); } catch (DaoException e) { throw new ConfigurationException(e); } } } }