You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mahout.apache.org by ra...@apache.org on 2018/06/27 14:52:02 UTC
[34/51] [partial] mahout git commit: MAHOUT-2042 and MAHOUT-2045
Delete directories which were moved/no longer in use
http://git-wip-us.apache.org/repos/asf/mahout/blob/e0573de3/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/hbase/HBaseDataModel.java
----------------------------------------------------------------------
diff --git a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/hbase/HBaseDataModel.java b/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/hbase/HBaseDataModel.java
deleted file mode 100644
index 9735ffe..0000000
--- a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/hbase/HBaseDataModel.java
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.mahout.cf.taste.impl.model.hbase;
-
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hbase.HBaseConfiguration;
-import org.apache.hadoop.hbase.HColumnDescriptor;
-import org.apache.hadoop.hbase.HTableDescriptor;
-import org.apache.hadoop.hbase.KeyValue;
-import org.apache.hadoop.hbase.client.Delete;
-import org.apache.hadoop.hbase.client.Get;
-import org.apache.hadoop.hbase.client.HBaseAdmin;
-import org.apache.hadoop.hbase.client.HTableFactory;
-import org.apache.hadoop.hbase.client.HTableInterface;
-import org.apache.hadoop.hbase.client.HTablePool;
-import org.apache.hadoop.hbase.client.Put;
-import org.apache.hadoop.hbase.client.Result;
-import org.apache.hadoop.hbase.client.ResultScanner;
-import org.apache.hadoop.hbase.client.Scan;
-import org.apache.hadoop.hbase.filter.FilterList;
-import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
-import org.apache.hadoop.hbase.filter.KeyOnlyFilter;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.mahout.cf.taste.common.NoSuchItemException;
-import org.apache.mahout.cf.taste.common.NoSuchUserException;
-import org.apache.mahout.cf.taste.common.Refreshable;
-import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.impl.common.FastIDSet;
-import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
-import org.apache.mahout.cf.taste.impl.model.GenericItemPreferenceArray;
-import org.apache.mahout.cf.taste.impl.model.GenericUserPreferenceArray;
-import org.apache.mahout.cf.taste.model.DataModel;
-import org.apache.mahout.cf.taste.model.PreferenceArray;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-
-/**
- * <p>Naive approach of storing one preference as one value in the table.
- * Preferences are indexed as (user, item) and (item, user) for O(1) lookups.</p>
- *
- * <p>The default table name is "taste", this can be set through a constructor
- * argument. Each row has a value starting with "i" or "u" followed by the
- * actual id encoded as a big endian long.</p>
- *
- * <p>E.g., "u\x00\x00\x00\x00\x00\x00\x04\xd2" is user 1234L</p>
- *
- * <p>There are two column families: "users" and "items".</p>
- *
- * <p>The "users" column family holds user->item preferences. Each userID is the
- * column qualifier and the value is the preference.</p>
- *
- * <p>The "items" column fmaily holds item->user preferences. Each itemID is the
- * column qualifier and the value is the preference.</p>
- *
- * <p>User IDs and item IDs are cached in a FastIDSet since it requires a full
- * table scan to build these sets. Preferences are not cached since they
- * are pretty cheap lookups in HBase (also caching the Preferences defeats
- * the purpose of a scalable storage engine like HBase).</p>
- */
-public final class HBaseDataModel implements DataModel, Closeable {
-
- private static final Logger log = LoggerFactory.getLogger(HBaseDataModel.class);
-
- private static final String DEFAULT_TABLE = "taste";
- private static final byte[] USERS_CF = Bytes.toBytes("users");
- private static final byte[] ITEMS_CF = Bytes.toBytes("items");
-
- private final HTablePool pool;
- private final String tableName;
-
- // Cache of user and item ids
- private volatile FastIDSet itemIDs;
- private volatile FastIDSet userIDs;
-
- public HBaseDataModel(String zkConnect) throws IOException {
- this(zkConnect, DEFAULT_TABLE);
- }
-
- public HBaseDataModel(String zkConnect, String tableName) throws IOException {
- log.info("Using HBase table {}", tableName);
- Configuration conf = HBaseConfiguration.create();
- conf.set("hbase.zookeeper.quorum", zkConnect);
- HTableFactory tableFactory = new HTableFactory();
- this.pool = new HTablePool(conf, 8, tableFactory);
- this.tableName = tableName;
-
- bootstrap(conf);
- // Warm the cache
- refresh(null);
- }
-
- public HBaseDataModel(HTablePool pool, String tableName, Configuration conf) throws IOException {
- log.info("Using HBase table {}", tableName);
- this.pool = pool;
- this.tableName = tableName;
-
- bootstrap(conf);
-
- // Warm the cache
- refresh(null);
- }
-
- public String getTableName() {
- return tableName;
- }
-
- /**
- * Create the table if it doesn't exist
- */
- private void bootstrap(Configuration conf) throws IOException {
- HTableDescriptor tDesc = new HTableDescriptor(Bytes.toBytes(tableName));
- tDesc.addFamily(new HColumnDescriptor(USERS_CF));
- tDesc.addFamily(new HColumnDescriptor(ITEMS_CF));
- try (HBaseAdmin admin = new HBaseAdmin(conf)) {
- admin.createTable(tDesc);
- log.info("Created table {}", tableName);
- }
- }
-
- /**
- * Prefix a user id with "u" and convert to byte[]
- */
- private static byte[] userToBytes(long userID) {
- ByteBuffer bb = ByteBuffer.allocate(9);
- bb.put((byte)0x75); // The letter "u"
- bb.putLong(userID);
- return bb.array();
- }
-
- /**
- * Prefix an item id with "i" and convert to byte[]
- */
- private static byte[] itemToBytes(long itemID) {
- ByteBuffer bb = ByteBuffer.allocate(9);
- bb.put((byte)0x69); // The letter "i"
- bb.putLong(itemID);
- return bb.array();
- }
-
- /**
- * Extract the id out of a prefix byte[] id
- */
- private static long bytesToUserOrItemID(byte[] ba) {
- ByteBuffer bb = ByteBuffer.wrap(ba);
- return bb.getLong(1);
- }
-
- /* DataModel interface */
-
- @Override
- public LongPrimitiveIterator getUserIDs() {
- return userIDs.iterator();
- }
-
- @Override
- public PreferenceArray getPreferencesFromUser(long userID) throws TasteException {
- Result result;
- try {
- HTableInterface table = pool.getTable(tableName);
- Get get = new Get(userToBytes(userID));
- get.addFamily(ITEMS_CF);
- result = table.get(get);
- table.close();
- } catch (IOException e) {
- throw new TasteException("Failed to retrieve user preferences from HBase", e);
- }
-
- if (result.isEmpty()) {
- throw new NoSuchUserException(userID);
- }
-
- SortedMap<byte[], byte[]> families = result.getFamilyMap(ITEMS_CF);
- PreferenceArray prefs = new GenericUserPreferenceArray(families.size());
- prefs.setUserID(0, userID);
- int i = 0;
- for (Map.Entry<byte[], byte[]> entry : families.entrySet()) {
- prefs.setItemID(i, Bytes.toLong(entry.getKey()));
- prefs.setValue(i, Bytes.toFloat(entry.getValue()));
- i++;
- }
- return prefs;
- }
-
- @Override
- public FastIDSet getItemIDsFromUser(long userID) throws TasteException {
- Result result;
- try {
- HTableInterface table = pool.getTable(tableName);
- Get get = new Get(userToBytes(userID));
- get.addFamily(ITEMS_CF);
- result = table.get(get);
- table.close();
- } catch (IOException e) {
- throw new TasteException("Failed to retrieve item IDs from HBase", e);
- }
-
- if (result.isEmpty()) {
- throw new NoSuchUserException(userID);
- }
-
- SortedMap<byte[],byte[]> families = result.getFamilyMap(ITEMS_CF);
- FastIDSet ids = new FastIDSet(families.size());
- for (byte[] family : families.keySet()) {
- ids.add(Bytes.toLong(family));
- }
- return ids;
- }
-
- @Override
- public LongPrimitiveIterator getItemIDs() {
- return itemIDs.iterator();
- }
-
- @Override
- public PreferenceArray getPreferencesForItem(long itemID) throws TasteException {
- Result result;
- try {
- HTableInterface table = pool.getTable(tableName);
- Get get = new Get(itemToBytes(itemID));
- get.addFamily(USERS_CF);
- result = table.get(get);
- table.close();
- } catch (IOException e) {
- throw new TasteException("Failed to retrieve item preferences from HBase", e);
- }
-
- if (result.isEmpty()) {
- throw new NoSuchItemException(itemID);
- }
-
- SortedMap<byte[], byte[]> families = result.getFamilyMap(USERS_CF);
- PreferenceArray prefs = new GenericItemPreferenceArray(families.size());
- prefs.setItemID(0, itemID);
- int i = 0;
- for (Map.Entry<byte[], byte[]> entry : families.entrySet()) {
- prefs.setUserID(i, Bytes.toLong(entry.getKey()));
- prefs.setValue(i, Bytes.toFloat(entry.getValue()));
- i++;
- }
- return prefs;
- }
-
- @Override
- public Float getPreferenceValue(long userID, long itemID) throws TasteException {
- Result result;
- try {
- HTableInterface table = pool.getTable(tableName);
- Get get = new Get(userToBytes(userID));
- get.addColumn(ITEMS_CF, Bytes.toBytes(itemID));
- result = table.get(get);
- table.close();
- } catch (IOException e) {
- throw new TasteException("Failed to retrieve user preferences from HBase", e);
- }
-
- if (result.isEmpty()) {
- throw new NoSuchUserException(userID);
- }
-
- if (result.containsColumn(ITEMS_CF, Bytes.toBytes(itemID))) {
- return Bytes.toFloat(result.getValue(ITEMS_CF, Bytes.toBytes(itemID)));
- } else {
- return null;
- }
- }
-
- @Override
- public Long getPreferenceTime(long userID, long itemID) throws TasteException {
- Result result;
- try {
- HTableInterface table = pool.getTable(tableName);
- Get get = new Get(userToBytes(userID));
- get.addColumn(ITEMS_CF, Bytes.toBytes(itemID));
- result = table.get(get);
- table.close();
- } catch (IOException e) {
- throw new TasteException("Failed to retrieve user preferences from HBase", e);
- }
-
- if (result.isEmpty()) {
- throw new NoSuchUserException(userID);
- }
-
- if (result.containsColumn(ITEMS_CF, Bytes.toBytes(itemID))) {
- KeyValue kv = result.getColumnLatest(ITEMS_CF, Bytes.toBytes(itemID));
- return kv.getTimestamp();
- } else {
- return null;
- }
- }
-
- @Override
- public int getNumItems() {
- return itemIDs.size();
- }
-
- @Override
- public int getNumUsers() {
- return userIDs.size();
- }
-
- @Override
- public int getNumUsersWithPreferenceFor(long itemID) throws TasteException {
- PreferenceArray prefs = getPreferencesForItem(itemID);
- return prefs.length();
- }
-
- @Override
- public int getNumUsersWithPreferenceFor(long itemID1, long itemID2) throws TasteException {
- Result[] results;
- try {
- HTableInterface table = pool.getTable(tableName);
- List<Get> gets = new ArrayList<>(2);
- gets.add(new Get(itemToBytes(itemID1)));
- gets.add(new Get(itemToBytes(itemID2)));
- gets.get(0).addFamily(USERS_CF);
- gets.get(1).addFamily(USERS_CF);
- results = table.get(gets);
- table.close();
- } catch (IOException e) {
- throw new TasteException("Failed to retrieve item preferences from HBase", e);
- }
-
- if (results[0].isEmpty()) {
- throw new NoSuchItemException(itemID1);
- }
- if (results[1].isEmpty()) {
- throw new NoSuchItemException(itemID2);
- }
-
- // First item
- Result result = results[0];
- SortedMap<byte[], byte[]> families = result.getFamilyMap(USERS_CF);
- FastIDSet idSet1 = new FastIDSet(families.size());
- for (byte[] id : families.keySet()) {
- idSet1.add(Bytes.toLong(id));
- }
-
- // Second item
- result = results[1];
- families = result.getFamilyMap(USERS_CF);
- FastIDSet idSet2 = new FastIDSet(families.size());
- for (byte[] id : families.keySet()) {
- idSet2.add(Bytes.toLong(id));
- }
-
- return idSet1.intersectionSize(idSet2);
- }
-
- @Override
- public void setPreference(long userID, long itemID, float value) throws TasteException {
- try {
- HTableInterface table = pool.getTable(tableName);
- List<Put> puts = new ArrayList<>(2);
- puts.add(new Put(userToBytes(userID)));
- puts.add(new Put(itemToBytes(itemID)));
- puts.get(0).add(ITEMS_CF, Bytes.toBytes(itemID), Bytes.toBytes(value));
- puts.get(1).add(USERS_CF, Bytes.toBytes(userID), Bytes.toBytes(value));
- table.put(puts);
- table.close();
- } catch (IOException e) {
- throw new TasteException("Failed to store preference in HBase", e);
- }
- }
-
- @Override
- public void removePreference(long userID, long itemID) throws TasteException {
- try {
- HTableInterface table = pool.getTable(tableName);
- List<Delete> deletes = new ArrayList<>(2);
- deletes.add(new Delete(userToBytes(userID)));
- deletes.add(new Delete(itemToBytes(itemID)));
- deletes.get(0).deleteColumns(ITEMS_CF, Bytes.toBytes(itemID));
- deletes.get(1).deleteColumns(USERS_CF, Bytes.toBytes(userID));
- table.delete(deletes);
- table.close();
- } catch (IOException e) {
- throw new TasteException("Failed to remove preference from HBase", e);
- }
- }
-
- @Override
- public boolean hasPreferenceValues() {
- return true;
- }
-
- @Override
- public float getMaxPreference() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public float getMinPreference() {
- throw new UnsupportedOperationException();
- }
-
- /* Closeable interface */
-
- @Override
- public void close() throws IOException {
- pool.close();
- }
-
- /* Refreshable interface */
-
- @Override
- public void refresh(Collection<Refreshable> alreadyRefreshed) {
- if (alreadyRefreshed == null || !alreadyRefreshed.contains(this)) {
- try {
- log.info("Refreshing item and user ID caches");
- long t1 = System.currentTimeMillis();
- refreshItemIDs();
- refreshUserIDs();
- long t2 = System.currentTimeMillis();
- log.info("Finished refreshing caches in {} ms", t2 - t1);
- } catch (IOException e) {
- throw new IllegalStateException("Could not reload DataModel", e);
- }
- }
- }
-
- /*
- * Refresh the item id cache. Warning: this does a large table scan
- */
- private synchronized void refreshItemIDs() throws IOException {
- // Get the list of item ids
- HTableInterface table = pool.getTable(tableName);
- Scan scan = new Scan(new byte[]{0x69}, new byte[]{0x70});
- scan.setFilter(new FilterList(FilterList.Operator.MUST_PASS_ALL, new KeyOnlyFilter(), new FirstKeyOnlyFilter()));
- ResultScanner scanner = table.getScanner(scan);
- Collection<Long> ids = new LinkedList<>();
- for (Result result : scanner) {
- ids.add(bytesToUserOrItemID(result.getRow()));
- }
- table.close();
-
- // Copy into FastIDSet
- FastIDSet itemIDs = new FastIDSet(ids.size());
- for (long l : ids) {
- itemIDs.add(l);
- }
-
- // Swap with the active
- this.itemIDs = itemIDs;
- }
-
- /*
- * Refresh the user id cache. Warning: this does a large table scan
- */
- private synchronized void refreshUserIDs() throws IOException {
- // Get the list of user ids
- HTableInterface table = pool.getTable(tableName);
- Scan scan = new Scan(new byte[]{0x75}, new byte[]{0x76});
- scan.setFilter(new FilterList(FilterList.Operator.MUST_PASS_ALL, new KeyOnlyFilter(), new FirstKeyOnlyFilter()));
- ResultScanner scanner = table.getScanner(scan);
- Collection<Long> ids = new LinkedList<>();
- for (Result result : scanner) {
- ids.add(bytesToUserOrItemID(result.getRow()));
- }
- table.close();
-
- // Copy into FastIDSet
- FastIDSet userIDs = new FastIDSet(ids.size());
- for (long l : ids) {
- userIDs.add(l);
- }
-
- // Swap with the active
- this.userIDs = userIDs;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mahout/blob/e0573de3/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractBooleanPrefJDBCDataModel.java
----------------------------------------------------------------------
diff --git a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractBooleanPrefJDBCDataModel.java b/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractBooleanPrefJDBCDataModel.java
deleted file mode 100644
index 79ca1ac..0000000
--- a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractBooleanPrefJDBCDataModel.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.mahout.cf.taste.impl.model.jdbc;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-
-import javax.sql.DataSource;
-
-import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.impl.model.BooleanPreference;
-import org.apache.mahout.cf.taste.model.Preference;
-import org.apache.mahout.common.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-
-public abstract class AbstractBooleanPrefJDBCDataModel extends AbstractJDBCDataModel {
-
- private static final Logger log = LoggerFactory.getLogger(AbstractBooleanPrefJDBCDataModel.class);
-
- static final String NO_SUCH_COLUMN = "NO_SUCH_COLUMN";
-
- private final String setPreferenceSQL;
-
- protected AbstractBooleanPrefJDBCDataModel(DataSource dataSource,
- String preferenceTable,
- String userIDColumn,
- String itemIDColumn,
- String preferenceColumn,
- String getPreferenceSQL,
- String getPreferenceTimeSQL,
- String getUserSQL,
- String getAllUsersSQL,
- String getNumItemsSQL,
- String getNumUsersSQL,
- String setPreferenceSQL,
- String removePreferenceSQL,
- String getUsersSQL,
- String getItemsSQL,
- String getPrefsForItemSQL,
- String getNumPreferenceForItemSQL,
- String getNumPreferenceForItemsSQL,
- String getMaxPreferenceSQL,
- String getMinPreferenceSQL) {
- super(dataSource,
- preferenceTable,
- userIDColumn,
- itemIDColumn,
- preferenceColumn,
- getPreferenceSQL,
- getPreferenceTimeSQL,
- getUserSQL,
- getAllUsersSQL,
- getNumItemsSQL,
- getNumUsersSQL,
- setPreferenceSQL,
- removePreferenceSQL,
- getUsersSQL,
- getItemsSQL,
- getPrefsForItemSQL,
- getNumPreferenceForItemSQL,
- getNumPreferenceForItemsSQL,
- getMaxPreferenceSQL,
- getMinPreferenceSQL);
- this.setPreferenceSQL = setPreferenceSQL;
- }
-
- @Override
- protected Preference buildPreference(ResultSet rs) throws SQLException {
- return new BooleanPreference(getLongColumn(rs, 1), getLongColumn(rs, 2));
- }
-
- @Override
- String getSetPreferenceSQL() {
- return setPreferenceSQL;
- }
-
- @Override
- public void setPreference(long userID, long itemID, float value) throws TasteException {
- Preconditions.checkArgument(!Float.isNaN(value), "NaN value");
- log.debug("Setting preference for user {}, item {}", userID, itemID);
-
- Connection conn = null;
- PreparedStatement stmt = null;
-
- try {
- conn = getDataSource().getConnection();
- stmt = conn.prepareStatement(setPreferenceSQL);
- setLongParameter(stmt, 1, userID);
- setLongParameter(stmt, 2, itemID);
-
- log.debug("Executing SQL update: {}", setPreferenceSQL);
- stmt.executeUpdate();
-
- } catch (SQLException sqle) {
- log.warn("Exception while setting preference", sqle);
- throw new TasteException(sqle);
- } finally {
- IOUtils.quietClose(null, stmt, conn);
- }
- }
-
- @Override
- public boolean hasPreferenceValues() {
- return false;
- }
-
- @Override
- public float getMaxPreference() {
- return 1.0f;
- }
-
- @Override
- public float getMinPreference() {
- return 1.0f;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mahout/blob/e0573de3/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractJDBCDataModel.java
----------------------------------------------------------------------
diff --git a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractJDBCDataModel.java b/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractJDBCDataModel.java
deleted file mode 100644
index 66f0a77..0000000
--- a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractJDBCDataModel.java
+++ /dev/null
@@ -1,787 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.mahout.cf.taste.impl.model.jdbc;
-
-import com.google.common.base.Preconditions;
-import org.apache.mahout.cf.taste.common.NoSuchItemException;
-import org.apache.mahout.cf.taste.common.NoSuchUserException;
-import org.apache.mahout.cf.taste.common.Refreshable;
-import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.impl.common.Cache;
-import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
-import org.apache.mahout.cf.taste.impl.common.FastIDSet;
-import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
-import org.apache.mahout.cf.taste.impl.common.Retriever;
-import org.apache.mahout.cf.taste.impl.common.jdbc.AbstractJDBCComponent;
-import org.apache.mahout.cf.taste.impl.common.jdbc.ResultSetIterator;
-import org.apache.mahout.cf.taste.impl.model.GenericItemPreferenceArray;
-import org.apache.mahout.cf.taste.impl.model.GenericPreference;
-import org.apache.mahout.cf.taste.impl.model.GenericUserPreferenceArray;
-import org.apache.mahout.cf.taste.model.JDBCDataModel;
-import org.apache.mahout.cf.taste.model.Preference;
-import org.apache.mahout.cf.taste.model.PreferenceArray;
-import org.apache.mahout.common.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import javax.sql.DataSource;
-
-/**
- * <p>
- * An abstract superclass for {@link JDBCDataModel} implementations, providing most of the common
- * functionality that any such implementation would need.
- * </p>
- *
- * <p>
- * Performance will be a concern with any {@link JDBCDataModel}. There are going to be lots of
- * simultaneous reads and some writes to one table. Make sure the table is set up optimally -- for example,
- * you'll want to establish indexes.
- * </p>
- *
- * <p>
- * You'll also want to use connection pooling of some kind. Most J2EE containers like Tomcat provide
- * connection pooling, so make sure the {@link DataSource} it exposes is using pooling. Outside a J2EE
- * container, you can use packages like Jakarta's <a href="http://jakarta.apache.org/commons/dbcp/">DBCP</a>
- * to create a {@link DataSource} on top of your database whose {@link Connection}s are pooled.
- * </p>
- */
-public abstract class AbstractJDBCDataModel extends AbstractJDBCComponent implements JDBCDataModel {
-
- private static final Logger log = LoggerFactory.getLogger(AbstractJDBCDataModel.class);
-
- public static final String DEFAULT_PREFERENCE_TABLE = "taste_preferences";
- public static final String DEFAULT_USER_ID_COLUMN = "user_id";
- public static final String DEFAULT_ITEM_ID_COLUMN = "item_id";
- public static final String DEFAULT_PREFERENCE_COLUMN = "preference";
- public static final String DEFAULT_PREFERENCE_TIME_COLUMN = "timestamp";
-
- private final DataSource dataSource;
- private final String preferenceTable;
- private final String userIDColumn;
- private final String itemIDColumn;
- private final String preferenceColumn;
- private final String getPreferenceSQL;
- private final String getPreferenceTimeSQL;
- private final String getUserSQL;
- private final String getAllUsersSQL;
- private final String getNumItemsSQL;
- private final String getNumUsersSQL;
- private final String setPreferenceSQL;
- private final String removePreferenceSQL;
- private final String getUsersSQL;
- private final String getItemsSQL;
- private final String getPrefsForItemSQL;
- private final String getNumPreferenceForItemsSQL;
- private final String getMaxPreferenceSQL;
- private final String getMinPreferenceSQL;
- private int cachedNumUsers;
- private int cachedNumItems;
- private final Cache<Long,Integer> itemPrefCounts;
- private float maxPreference;
- private float minPreference;
-
- protected AbstractJDBCDataModel(DataSource dataSource,
- String getPreferenceSQL,
- String getPreferenceTimeSQL,
- String getUserSQL,
- String getAllUsersSQL,
- String getNumItemsSQL,
- String getNumUsersSQL,
- String setPreferenceSQL,
- String removePreferenceSQL,
- String getUsersSQL,
- String getItemsSQL,
- String getPrefsForItemSQL,
- String getNumPreferenceForItemSQL,
- String getNumPreferenceForItemsSQL,
- String getMaxPreferenceSQL,
- String getMinPreferenceSQL) {
- this(dataSource,
- DEFAULT_PREFERENCE_TABLE,
- DEFAULT_USER_ID_COLUMN,
- DEFAULT_ITEM_ID_COLUMN,
- DEFAULT_PREFERENCE_COLUMN,
- getPreferenceSQL,
- getPreferenceTimeSQL,
- getUserSQL,
- getAllUsersSQL,
- getNumItemsSQL,
- getNumUsersSQL,
- setPreferenceSQL,
- removePreferenceSQL,
- getUsersSQL,
- getItemsSQL,
- getPrefsForItemSQL,
- getNumPreferenceForItemSQL,
- getNumPreferenceForItemsSQL,
- getMaxPreferenceSQL,
- getMinPreferenceSQL);
- }
-
- protected AbstractJDBCDataModel(DataSource dataSource,
- String preferenceTable,
- String userIDColumn,
- String itemIDColumn,
- String preferenceColumn,
- String getPreferenceSQL,
- String getPreferenceTimeSQL,
- String getUserSQL,
- String getAllUsersSQL,
- String getNumItemsSQL,
- String getNumUsersSQL,
- String setPreferenceSQL,
- String removePreferenceSQL,
- String getUsersSQL,
- String getItemsSQL,
- String getPrefsForItemSQL,
- String getNumPreferenceForItemSQL,
- String getNumPreferenceForItemsSQL,
- String getMaxPreferenceSQL,
- String getMinPreferenceSQL) {
-
- log.debug("Creating AbstractJDBCModel...");
-
- AbstractJDBCComponent.checkNotNullAndLog("preferenceTable", preferenceTable);
- AbstractJDBCComponent.checkNotNullAndLog("userIDColumn", userIDColumn);
- AbstractJDBCComponent.checkNotNullAndLog("itemIDColumn", itemIDColumn);
- AbstractJDBCComponent.checkNotNullAndLog("preferenceColumn", preferenceColumn);
-
- AbstractJDBCComponent.checkNotNullAndLog("dataSource", dataSource);
- AbstractJDBCComponent.checkNotNullAndLog("getUserSQL", getUserSQL);
- AbstractJDBCComponent.checkNotNullAndLog("getAllUsersSQL", getAllUsersSQL);
- AbstractJDBCComponent.checkNotNullAndLog("getPreferenceSQL", getPreferenceSQL);
- // getPreferenceTimeSQL can be null
- AbstractJDBCComponent.checkNotNullAndLog("getNumItemsSQL", getNumItemsSQL);
- AbstractJDBCComponent.checkNotNullAndLog("getNumUsersSQL", getNumUsersSQL);
- AbstractJDBCComponent.checkNotNullAndLog("setPreferenceSQL", setPreferenceSQL);
- AbstractJDBCComponent.checkNotNullAndLog("removePreferenceSQL", removePreferenceSQL);
- AbstractJDBCComponent.checkNotNullAndLog("getUsersSQL", getUsersSQL);
- AbstractJDBCComponent.checkNotNullAndLog("getItemsSQL", getItemsSQL);
- AbstractJDBCComponent.checkNotNullAndLog("getPrefsForItemSQL", getPrefsForItemSQL);
- AbstractJDBCComponent.checkNotNullAndLog("getNumPreferenceForItemSQL", getNumPreferenceForItemSQL);
- AbstractJDBCComponent.checkNotNullAndLog("getNumPreferenceForItemsSQL", getNumPreferenceForItemsSQL);
- AbstractJDBCComponent.checkNotNullAndLog("getMaxPreferenceSQL", getMaxPreferenceSQL);
- AbstractJDBCComponent.checkNotNullAndLog("getMinPreferenceSQL", getMinPreferenceSQL);
-
- if (!(dataSource instanceof ConnectionPoolDataSource)) {
- log.warn("You are not using ConnectionPoolDataSource. Make sure your DataSource pools connections "
- + "to the database itself, or database performance will be severely reduced.");
- }
-
- this.preferenceTable = preferenceTable;
- this.userIDColumn = userIDColumn;
- this.itemIDColumn = itemIDColumn;
- this.preferenceColumn = preferenceColumn;
-
- this.dataSource = dataSource;
- this.getPreferenceSQL = getPreferenceSQL;
- this.getPreferenceTimeSQL = getPreferenceTimeSQL;
- this.getUserSQL = getUserSQL;
- this.getAllUsersSQL = getAllUsersSQL;
- this.getNumItemsSQL = getNumItemsSQL;
- this.getNumUsersSQL = getNumUsersSQL;
- this.setPreferenceSQL = setPreferenceSQL;
- this.removePreferenceSQL = removePreferenceSQL;
- this.getUsersSQL = getUsersSQL;
- this.getItemsSQL = getItemsSQL;
- this.getPrefsForItemSQL = getPrefsForItemSQL;
- //this.getNumPreferenceForItemSQL = getNumPreferenceForItemSQL;
- this.getNumPreferenceForItemsSQL = getNumPreferenceForItemsSQL;
- this.getMaxPreferenceSQL = getMaxPreferenceSQL;
- this.getMinPreferenceSQL = getMinPreferenceSQL;
-
- this.cachedNumUsers = -1;
- this.cachedNumItems = -1;
- this.itemPrefCounts = new Cache<>(new ItemPrefCountRetriever(getNumPreferenceForItemSQL));
-
- this.maxPreference = Float.NaN;
- this.minPreference = Float.NaN;
- }
-
- /** @return the {@link DataSource} that this instance is using */
- @Override
- public DataSource getDataSource() {
- return dataSource;
- }
-
- public String getPreferenceTable() {
- return preferenceTable;
- }
-
- public String getUserIDColumn() {
- return userIDColumn;
- }
-
- public String getItemIDColumn() {
- return itemIDColumn;
- }
-
- public String getPreferenceColumn() {
- return preferenceColumn;
- }
-
- String getSetPreferenceSQL() {
- return setPreferenceSQL;
- }
-
- @Override
- public LongPrimitiveIterator getUserIDs() throws TasteException {
- log.debug("Retrieving all users...");
- try {
- return new ResultSetIDIterator(getUsersSQL);
- } catch (SQLException sqle) {
- throw new TasteException(sqle);
- }
- }
-
- /**
- * @throws NoSuchUserException
- * if there is no such user
- */
- @Override
- public PreferenceArray getPreferencesFromUser(long userID) throws TasteException {
-
- log.debug("Retrieving user ID '{}'", userID);
-
- Connection conn = null;
- PreparedStatement stmt = null;
- ResultSet rs = null;
-
- try {
- conn = dataSource.getConnection();
- stmt = conn.prepareStatement(getUserSQL, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
- stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
- stmt.setFetchSize(getFetchSize());
- setLongParameter(stmt, 1, userID);
-
- log.debug("Executing SQL query: {}", getUserSQL);
- rs = stmt.executeQuery();
-
- List<Preference> prefs = new ArrayList<>();
- while (rs.next()) {
- prefs.add(buildPreference(rs));
- }
-
- if (prefs.isEmpty()) {
- throw new NoSuchUserException(userID);
- }
-
- return new GenericUserPreferenceArray(prefs);
-
- } catch (SQLException sqle) {
- log.warn("Exception while retrieving user", sqle);
- throw new TasteException(sqle);
- } finally {
- IOUtils.quietClose(rs, stmt, conn);
- }
-
- }
-
- @Override
- public FastByIDMap<PreferenceArray> exportWithPrefs() throws TasteException {
- log.debug("Exporting all data");
-
- Connection conn = null;
- Statement stmt = null;
- ResultSet rs = null;
-
- FastByIDMap<PreferenceArray> result = new FastByIDMap<>();
-
- try {
- conn = dataSource.getConnection();
- stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
- stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
- stmt.setFetchSize(getFetchSize());
-
- log.debug("Executing SQL query: {}", getAllUsersSQL);
- rs = stmt.executeQuery(getAllUsersSQL);
-
- Long currentUserID = null;
- List<Preference> currentPrefs = new ArrayList<>();
- while (rs.next()) {
- long nextUserID = getLongColumn(rs, 1);
- if (currentUserID != null && !currentUserID.equals(nextUserID) && !currentPrefs.isEmpty()) {
- result.put(currentUserID, new GenericUserPreferenceArray(currentPrefs));
- currentPrefs.clear();
- }
- currentPrefs.add(buildPreference(rs));
- currentUserID = nextUserID;
- }
- if (!currentPrefs.isEmpty()) {
- result.put(currentUserID, new GenericUserPreferenceArray(currentPrefs));
- }
-
- return result;
-
- } catch (SQLException sqle) {
- log.warn("Exception while exporting all data", sqle);
- throw new TasteException(sqle);
- } finally {
- IOUtils.quietClose(rs, stmt, conn);
-
- }
- }
-
- @Override
- public FastByIDMap<FastIDSet> exportWithIDsOnly() throws TasteException {
- log.debug("Exporting all data");
-
- Connection conn = null;
- Statement stmt = null;
- ResultSet rs = null;
-
- FastByIDMap<FastIDSet> result = new FastByIDMap<>();
-
- try {
- conn = dataSource.getConnection();
- stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
- stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
- stmt.setFetchSize(getFetchSize());
-
- log.debug("Executing SQL query: {}", getAllUsersSQL);
- rs = stmt.executeQuery(getAllUsersSQL);
-
- boolean currentUserIDSet = false;
- long currentUserID = 0L; // value isn't used
- FastIDSet currentItemIDs = new FastIDSet(2);
- while (rs.next()) {
- long nextUserID = getLongColumn(rs, 1);
- if (currentUserIDSet && currentUserID != nextUserID && !currentItemIDs.isEmpty()) {
- result.put(currentUserID, currentItemIDs);
- currentItemIDs = new FastIDSet(2);
- }
- currentItemIDs.add(getLongColumn(rs, 2));
- currentUserID = nextUserID;
- currentUserIDSet = true;
- }
- if (!currentItemIDs.isEmpty()) {
- result.put(currentUserID, currentItemIDs);
- }
-
- return result;
-
- } catch (SQLException sqle) {
- log.warn("Exception while exporting all data", sqle);
- throw new TasteException(sqle);
- } finally {
- IOUtils.quietClose(rs, stmt, conn);
-
- }
- }
-
- /**
- * @throws NoSuchUserException
- * if there is no such user
- */
- @Override
- public FastIDSet getItemIDsFromUser(long userID) throws TasteException {
-
- log.debug("Retrieving items for user ID '{}'", userID);
-
- Connection conn = null;
- PreparedStatement stmt = null;
- ResultSet rs = null;
-
- try {
- conn = dataSource.getConnection();
- stmt = conn.prepareStatement(getUserSQL, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
- stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
- stmt.setFetchSize(getFetchSize());
- setLongParameter(stmt, 1, userID);
-
- log.debug("Executing SQL query: {}", getUserSQL);
- rs = stmt.executeQuery();
-
- FastIDSet result = new FastIDSet();
- while (rs.next()) {
- result.add(getLongColumn(rs, 2));
- }
-
- if (result.isEmpty()) {
- throw new NoSuchUserException(userID);
- }
-
- return result;
-
- } catch (SQLException sqle) {
- log.warn("Exception while retrieving item s", sqle);
- throw new TasteException(sqle);
- } finally {
- IOUtils.quietClose(rs, stmt, conn);
- }
-
- }
-
- @Override
- public Float getPreferenceValue(long userID, long itemID) throws TasteException {
- log.debug("Retrieving preferences for item ID '{}'", itemID);
- Connection conn = null;
- PreparedStatement stmt = null;
- ResultSet rs = null;
- try {
- conn = dataSource.getConnection();
- stmt = conn.prepareStatement(getPreferenceSQL, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
- stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
- stmt.setFetchSize(1);
- setLongParameter(stmt, 1, userID);
- setLongParameter(stmt, 2, itemID);
-
- log.debug("Executing SQL query: {}", getPreferenceSQL);
- rs = stmt.executeQuery();
- if (rs.next()) {
- return rs.getFloat(1);
- } else {
- return null;
- }
- } catch (SQLException sqle) {
- log.warn("Exception while retrieving prefs for item", sqle);
- throw new TasteException(sqle);
- } finally {
- IOUtils.quietClose(rs, stmt, conn);
- }
- }
-
- @Override
- public Long getPreferenceTime(long userID, long itemID) throws TasteException {
- if (getPreferenceTimeSQL == null) {
- return null;
- }
- log.debug("Retrieving preference time for item ID '{}'", itemID);
- Connection conn = null;
- PreparedStatement stmt = null;
- ResultSet rs = null;
- try {
- conn = dataSource.getConnection();
- stmt = conn.prepareStatement(getPreferenceTimeSQL, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
- stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
- stmt.setFetchSize(1);
- setLongParameter(stmt, 1, userID);
- setLongParameter(stmt, 2, itemID);
-
- log.debug("Executing SQL query: {}", getPreferenceTimeSQL);
- rs = stmt.executeQuery();
- if (rs.next()) {
- return rs.getLong(1);
- } else {
- return null;
- }
- } catch (SQLException sqle) {
- log.warn("Exception while retrieving time for item", sqle);
- throw new TasteException(sqle);
- } finally {
- IOUtils.quietClose(rs, stmt, conn);
- }
- }
-
- @Override
- public LongPrimitiveIterator getItemIDs() throws TasteException {
- log.debug("Retrieving all items...");
- try {
- return new ResultSetIDIterator(getItemsSQL);
- } catch (SQLException sqle) {
- throw new TasteException(sqle);
- }
- }
-
- @Override
- public PreferenceArray getPreferencesForItem(long itemID) throws TasteException {
- List<Preference> list = doGetPreferencesForItem(itemID);
- if (list.isEmpty()) {
- throw new NoSuchItemException(itemID);
- }
- return new GenericItemPreferenceArray(list);
- }
-
- protected List<Preference> doGetPreferencesForItem(long itemID) throws TasteException {
- log.debug("Retrieving preferences for item ID '{}'", itemID);
- Connection conn = null;
- PreparedStatement stmt = null;
- ResultSet rs = null;
- try {
- conn = dataSource.getConnection();
- stmt = conn.prepareStatement(getPrefsForItemSQL, ResultSet.TYPE_FORWARD_ONLY,
- ResultSet.CONCUR_READ_ONLY);
- stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
- stmt.setFetchSize(getFetchSize());
- setLongParameter(stmt, 1, itemID);
-
- log.debug("Executing SQL query: {}", getPrefsForItemSQL);
- rs = stmt.executeQuery();
- List<Preference> prefs = new ArrayList<>();
- while (rs.next()) {
- prefs.add(buildPreference(rs));
- }
- return prefs;
- } catch (SQLException sqle) {
- log.warn("Exception while retrieving prefs for item", sqle);
- throw new TasteException(sqle);
- } finally {
- IOUtils.quietClose(rs, stmt, conn);
- }
- }
-
- @Override
- public int getNumItems() throws TasteException {
- if (cachedNumItems < 0) {
- cachedNumItems = getNumThings("items", getNumItemsSQL);
- }
- return cachedNumItems;
- }
-
- @Override
- public int getNumUsers() throws TasteException {
- if (cachedNumUsers < 0) {
- cachedNumUsers = getNumThings("users", getNumUsersSQL);
- }
- return cachedNumUsers;
- }
-
- @Override
- public int getNumUsersWithPreferenceFor(long itemID) throws TasteException {
- return itemPrefCounts.get(itemID);
- }
-
- @Override
- public int getNumUsersWithPreferenceFor(long itemID1, long itemID2) throws TasteException {
- return getNumThings("user preferring items", getNumPreferenceForItemsSQL, itemID1, itemID2);
- }
-
- private int getNumThings(String name, String sql, long... args) throws TasteException {
- log.debug("Retrieving number of {} in model", name);
- Connection conn = null;
- PreparedStatement stmt = null;
- ResultSet rs = null;
- try {
- conn = dataSource.getConnection();
- stmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
- stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
- stmt.setFetchSize(getFetchSize());
- if (args != null) {
- for (int i = 1; i <= args.length; i++) {
- setLongParameter(stmt, i, args[i - 1]);
- }
- }
- log.debug("Executing SQL query: {}", sql);
- rs = stmt.executeQuery();
- rs.next();
- return rs.getInt(1);
- } catch (SQLException sqle) {
- log.warn("Exception while retrieving number of {}", name, sqle);
- throw new TasteException(sqle);
- } finally {
- IOUtils.quietClose(rs, stmt, conn);
- }
- }
-
- @Override
- public void setPreference(long userID, long itemID, float value) throws TasteException {
- Preconditions.checkArgument(!Float.isNaN(value), "NaN value");
-
- log.debug("Setting preference for user {}, item {}", userID, itemID);
-
- Connection conn = null;
- PreparedStatement stmt = null;
-
- try {
- conn = dataSource.getConnection();
- stmt = conn.prepareStatement(setPreferenceSQL);
- setLongParameter(stmt, 1, userID);
- setLongParameter(stmt, 2, itemID);
- stmt.setDouble(3, value);
- stmt.setDouble(4, value);
-
- log.debug("Executing SQL update: {}", setPreferenceSQL);
- stmt.executeUpdate();
-
- } catch (SQLException sqle) {
- log.warn("Exception while setting preference", sqle);
- throw new TasteException(sqle);
- } finally {
- IOUtils.quietClose(null, stmt, conn);
- }
- }
-
- @Override
- public void removePreference(long userID, long itemID) throws TasteException {
-
- log.debug("Removing preference for user '{}', item '{}'", userID, itemID);
-
- Connection conn = null;
- PreparedStatement stmt = null;
-
- try {
- conn = dataSource.getConnection();
- stmt = conn.prepareStatement(removePreferenceSQL);
- setLongParameter(stmt, 1, userID);
- setLongParameter(stmt, 2, itemID);
-
- log.debug("Executing SQL update: {}", removePreferenceSQL);
- stmt.executeUpdate();
-
- } catch (SQLException sqle) {
- log.warn("Exception while removing preference", sqle);
- throw new TasteException(sqle);
- } finally {
- IOUtils.quietClose(null, stmt, conn);
- }
- }
-
- @Override
- public void refresh(Collection<Refreshable> alreadyRefreshed) {
- cachedNumUsers = -1;
- cachedNumItems = -1;
- minPreference = Float.NaN;
- maxPreference = Float.NaN;
- itemPrefCounts.clear();
- }
-
- @Override
- public boolean hasPreferenceValues() {
- return true;
- }
-
- @Override
- public float getMaxPreference() {
- if (Float.isNaN(maxPreference)) {
- Connection conn = null;
- PreparedStatement stmt = null;
- ResultSet rs = null;
- try {
- conn = dataSource.getConnection();
- stmt = conn.prepareStatement(getMaxPreferenceSQL);
-
- log.debug("Executing SQL query: {}", getMaxPreferenceSQL);
- rs = stmt.executeQuery();
- rs.next();
- maxPreference = rs.getFloat(1);
-
- } catch (SQLException sqle) {
- log.warn("Exception while removing preference", sqle);
- // do nothing
- } finally {
- IOUtils.quietClose(rs, stmt, conn);
- }
- }
- return maxPreference;
- }
-
- @Override
- public float getMinPreference() {
- if (Float.isNaN(minPreference)) {
- Connection conn = null;
- PreparedStatement stmt = null;
- ResultSet rs = null;
- try {
- conn = dataSource.getConnection();
- stmt = conn.prepareStatement(getMinPreferenceSQL);
-
- log.debug("Executing SQL query: {}", getMinPreferenceSQL);
- rs = stmt.executeQuery();
- rs.next();
- minPreference = rs.getFloat(1);
-
- } catch (SQLException sqle) {
- log.warn("Exception while removing preference", sqle);
- // do nothing
- } finally {
- IOUtils.quietClose(rs, stmt, conn);
- }
- }
- return minPreference;
- }
-
- // Some overrideable methods to customize the class behavior:
-
- protected Preference buildPreference(ResultSet rs) throws SQLException {
- return new GenericPreference(getLongColumn(rs, 1), getLongColumn(rs, 2), rs.getFloat(3));
- }
-
- /**
- * Subclasses may wish to override this if ID values in the file are not numeric. This provides a hook by
- * which subclasses can inject an {@link org.apache.mahout.cf.taste.model.IDMigrator} to perform
- * translation.
- */
- protected long getLongColumn(ResultSet rs, int position) throws SQLException {
- return rs.getLong(position);
- }
-
- /**
- * Subclasses may wish to override this if ID values in the file are not numeric. This provides a hook by
- * which subclasses can inject an {@link org.apache.mahout.cf.taste.model.IDMigrator} to perform
- * translation.
- */
- protected void setLongParameter(PreparedStatement stmt, int position, long value) throws SQLException {
- stmt.setLong(position, value);
- }
-
- /**
- * <p>
- * An {@link java.util.Iterator} which returns items from a {@link ResultSet}. This is a useful way to
- * iterate over all user data since it does not require all data to be read into memory at once. It does
- * however require that the DB connection be held open. Note that this class will only release database
- * resources after {@link #hasNext()} has been called and has returned {@code false}; callers should
- * make sure to "drain" the entire set of data to avoid tying up database resources.
- * </p>
- */
- private final class ResultSetIDIterator extends ResultSetIterator<Long> implements LongPrimitiveIterator {
-
- private ResultSetIDIterator(String sql) throws SQLException {
- super(dataSource, sql);
- }
-
- @Override
- protected Long parseElement(ResultSet resultSet) throws SQLException {
- return getLongColumn(resultSet, 1);
- }
-
- @Override
- public long nextLong() {
- return next();
- }
-
- /**
- * @throws UnsupportedOperationException
- */
- @Override
- public long peek() {
- // This could be supported; is it worth it?
- throw new UnsupportedOperationException();
- }
- }
-
- private final class ItemPrefCountRetriever implements Retriever<Long,Integer> {
- private final String getNumPreferenceForItemSQL;
-
- private ItemPrefCountRetriever(String getNumPreferenceForItemSQL) {
- this.getNumPreferenceForItemSQL = getNumPreferenceForItemSQL;
- }
-
- @Override
- public Integer get(Long key) throws TasteException {
- return getNumThings("user preferring item", getNumPreferenceForItemSQL, key);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mahout/blob/e0573de3/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/ConnectionPoolDataSource.java
----------------------------------------------------------------------
diff --git a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/ConnectionPoolDataSource.java b/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/ConnectionPoolDataSource.java
deleted file mode 100644
index ff7f661..0000000
--- a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/ConnectionPoolDataSource.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.mahout.cf.taste.impl.model.jdbc;
-
-import java.io.PrintWriter;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
-import java.util.logging.Logger;
-
-import javax.sql.DataSource;
-
-import org.apache.commons.dbcp.ConnectionFactory;
-import org.apache.commons.dbcp.PoolableConnectionFactory;
-import org.apache.commons.dbcp.PoolingDataSource;
-import org.apache.commons.pool.impl.GenericObjectPool;
-
-import com.google.common.base.Preconditions;
-
-/**
- * <p>
- * A wrapper {@link DataSource} which pools connections.
- * </p>
- */
-public final class ConnectionPoolDataSource implements DataSource {
-
- private final DataSource delegate;
-
- public ConnectionPoolDataSource(DataSource underlyingDataSource) {
- Preconditions.checkNotNull(underlyingDataSource);
- ConnectionFactory connectionFactory = new ConfiguringConnectionFactory(underlyingDataSource);
- GenericObjectPool objectPool = new GenericObjectPool();
- objectPool.setTestOnBorrow(false);
- objectPool.setTestOnReturn(false);
- objectPool.setTestWhileIdle(true);
- objectPool.setTimeBetweenEvictionRunsMillis(60 * 1000L);
- // Constructor actually sets itself as factory on pool
- new PoolableConnectionFactory(connectionFactory, objectPool, null, "SELECT 1", false, false);
- delegate = new PoolingDataSource(objectPool);
- }
-
- @Override
- public Connection getConnection() throws SQLException {
- return delegate.getConnection();
- }
-
- @Override
- public Connection getConnection(String username, String password) throws SQLException {
- return delegate.getConnection(username, password);
- }
-
- @Override
- public PrintWriter getLogWriter() throws SQLException {
- return delegate.getLogWriter();
- }
-
- @Override
- public void setLogWriter(PrintWriter printWriter) throws SQLException {
- delegate.setLogWriter(printWriter);
- }
-
- @Override
- public void setLoginTimeout(int timeout) throws SQLException {
- delegate.setLoginTimeout(timeout);
- }
-
- @Override
- public int getLoginTimeout() throws SQLException {
- return delegate.getLoginTimeout();
- }
-
- @Override
- public <T> T unwrap(Class<T> iface) throws SQLException {
- return delegate.unwrap(iface);
- }
-
- @Override
- public boolean isWrapperFor(Class<?> iface) throws SQLException {
- return delegate.isWrapperFor(iface);
- }
-
- // This exists for compatibility with Java 7 / JDBC 4.1, but doesn't exist
- // in Java 6. In Java 7 it would @Override, but not in 6.
- // @Override
- public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- throw new SQLFeatureNotSupportedException();
- }
-
- private static class ConfiguringConnectionFactory implements ConnectionFactory {
-
- private final DataSource underlyingDataSource;
-
- ConfiguringConnectionFactory(DataSource underlyingDataSource) {
- this.underlyingDataSource = underlyingDataSource;
- }
-
- @Override
- public Connection createConnection() throws SQLException {
- Connection connection = underlyingDataSource.getConnection();
- connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
- connection.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
- return connection;
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mahout/blob/e0573de3/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/GenericJDBCDataModel.java
----------------------------------------------------------------------
diff --git a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/GenericJDBCDataModel.java b/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/GenericJDBCDataModel.java
deleted file mode 100644
index 5dd0be9..0000000
--- a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/GenericJDBCDataModel.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.mahout.cf.taste.impl.model.jdbc;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-import com.google.common.io.Closeables;
-import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.impl.common.jdbc.AbstractJDBCComponent;
-
-/**
- * <p>
- * A generic {@link org.apache.mahout.cf.taste.model.DataModel} designed for use with other JDBC data sources;
- * one just specifies all necessary SQL queries to the constructor here. Optionally, the queries can be
- * specified from a {@link Properties} object, {@link File}, or {@link InputStream}. This class is most
- * appropriate when other existing implementations of {@link AbstractJDBCDataModel} are not suitable. If you
- * are using this class to support a major database, consider contributing a specialized implementation of
- * {@link AbstractJDBCDataModel} to the project for this database.
- * </p>
- */
-public final class GenericJDBCDataModel extends AbstractJDBCDataModel {
-
- public static final String DATA_SOURCE_KEY = "dataSource";
- public static final String GET_PREFERENCE_SQL_KEY = "getPreferenceSQL";
- public static final String GET_PREFERENCE_TIME_SQL_KEY = "getPreferenceTimeSQL";
- public static final String GET_USER_SQL_KEY = "getUserSQL";
- public static final String GET_ALL_USERS_SQL_KEY = "getAllUsersSQL";
- public static final String GET_NUM_USERS_SQL_KEY = "getNumUsersSQL";
- public static final String GET_NUM_ITEMS_SQL_KEY = "getNumItemsSQL";
- public static final String SET_PREFERENCE_SQL_KEY = "setPreferenceSQL";
- public static final String REMOVE_PREFERENCE_SQL_KEY = "removePreferenceSQL";
- public static final String GET_USERS_SQL_KEY = "getUsersSQL";
- public static final String GET_ITEMS_SQL_KEY = "getItemsSQL";
- public static final String GET_PREFS_FOR_ITEM_SQL_KEY = "getPrefsForItemSQL";
- public static final String GET_NUM_PREFERENCE_FOR_ITEM_KEY = "getNumPreferenceForItemSQL";
- public static final String GET_NUM_PREFERENCE_FOR_ITEMS_KEY = "getNumPreferenceForItemsSQL";
- public static final String GET_MAX_PREFERENCE_KEY = "getMaxPreferenceSQL";
- public static final String GET_MIN_PREFERENCE_KEY = "getMinPreferenceSQL";
-
- /**
- * <p>
- * Specifies all SQL queries in a {@link Properties} object. See the {@code *_KEY} constants in this
- * class (e.g. {@link #GET_USER_SQL_KEY}) for a list of all keys which must map to a value in this object.
- * </p>
- *
- * @param props
- * {@link Properties} object containing values
- * @throws TasteException
- * if anything goes wrong during initialization
- */
- public GenericJDBCDataModel(Properties props) throws TasteException {
- super(AbstractJDBCComponent.lookupDataSource(props.getProperty(DATA_SOURCE_KEY)),
- props.getProperty(GET_PREFERENCE_SQL_KEY),
- props.getProperty(GET_PREFERENCE_TIME_SQL_KEY),
- props.getProperty(GET_USER_SQL_KEY),
- props.getProperty(GET_ALL_USERS_SQL_KEY),
- props.getProperty(GET_NUM_ITEMS_SQL_KEY),
- props.getProperty(GET_NUM_USERS_SQL_KEY),
- props.getProperty(SET_PREFERENCE_SQL_KEY),
- props.getProperty(REMOVE_PREFERENCE_SQL_KEY),
- props.getProperty(GET_USERS_SQL_KEY),
- props.getProperty(GET_ITEMS_SQL_KEY),
- props.getProperty(GET_PREFS_FOR_ITEM_SQL_KEY),
- props.getProperty(GET_NUM_PREFERENCE_FOR_ITEM_KEY),
- props.getProperty(GET_NUM_PREFERENCE_FOR_ITEMS_KEY),
- props.getProperty(GET_MAX_PREFERENCE_KEY),
- props.getProperty(GET_MIN_PREFERENCE_KEY));
- }
-
- /**
- * <p>
- * See {@link #GenericJDBCDataModel(Properties)}. This constructor reads values from a file
- * instead, as if with {@link Properties#load(InputStream)}. So, the file should be in standard Java
- * properties file format -- containing {@code key=value} pairs, one per line.
- * </p>
- *
- * @param propertiesFile
- * properties file
- * @throws TasteException
- * if anything goes wrong during initialization
- */
- public GenericJDBCDataModel(File propertiesFile) throws TasteException {
- this(getPropertiesFromFile(propertiesFile));
- }
-
- /**
- * <p>
- * See {@link #GenericJDBCDataModel(Properties)}. This constructor reads values from a resource available in
- * the classpath, as if with {@link Class#getResourceAsStream(String)} and
- * {@link Properties#load(InputStream)}. This is useful if your configuration file is, for example, packaged
- * in a JAR file that is in the classpath.
- * </p>
- *
- * @param resourcePath
- * path to resource in classpath (e.g. "/com/foo/TasteSQLQueries.properties")
- * @throws TasteException
- * if anything goes wrong during initialization
- */
- public GenericJDBCDataModel(String resourcePath) throws TasteException {
- this(getPropertiesFromStream(GenericJDBCDataModel.class
- .getResourceAsStream(resourcePath)));
- }
-
- private static Properties getPropertiesFromFile(File file) throws TasteException {
- try {
- return getPropertiesFromStream(new FileInputStream(file));
- } catch (FileNotFoundException fnfe) {
- throw new TasteException(fnfe);
- }
- }
-
- private static Properties getPropertiesFromStream(InputStream is) throws TasteException {
- try {
- try {
- Properties props = new Properties();
- props.load(is);
- return props;
- } finally {
- Closeables.close(is, true);
- }
- } catch (IOException ioe) {
- throw new TasteException(ioe);
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mahout/blob/e0573de3/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLBooleanPrefJDBCDataModel.java
----------------------------------------------------------------------
diff --git a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLBooleanPrefJDBCDataModel.java b/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLBooleanPrefJDBCDataModel.java
deleted file mode 100644
index 3e9de2c..0000000
--- a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLBooleanPrefJDBCDataModel.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.mahout.cf.taste.impl.model.jdbc;
-
-import javax.sql.DataSource;
-
-import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.impl.common.jdbc.AbstractJDBCComponent;
-
-/**
- * <p>
- * See also {@link MySQLJDBCDataModel} -- same except deals with a table without preference info:
- * </p>
- *
- * <p>
- *
- * <pre>
- * CREATE TABLE taste_preferences (
- * user_id BIGINT NOT NULL,
- * item_id BIGINT NOT NULL,
- * PRIMARY KEY (user_id, item_id),
- * INDEX (user_id),
- * INDEX (item_id)
- * )
- * </pre>
- *
- * </p>
- */
-public class MySQLBooleanPrefJDBCDataModel extends AbstractBooleanPrefJDBCDataModel {
-
- /**
- * <p>
- * Creates a {@link MySQLBooleanPrefJDBCDataModel} using the default {@link javax.sql.DataSource} (named
- * {@link #DEFAULT_DATASOURCE_NAME} and default table/column names.
- * </p>
- *
- * @throws org.apache.mahout.cf.taste.common.TasteException
- * if {@link javax.sql.DataSource} can't be found
- */
- public MySQLBooleanPrefJDBCDataModel() throws TasteException {
- this(DEFAULT_DATASOURCE_NAME);
- }
-
- /**
- * <p>
- * Creates a {@link MySQLBooleanPrefJDBCDataModel} using the default {@link javax.sql.DataSource} found
- * under the given name, and using default table/column names.
- * </p>
- *
- * @param dataSourceName
- * name of {@link javax.sql.DataSource} to look up
- * @throws org.apache.mahout.cf.taste.common.TasteException
- * if {@link javax.sql.DataSource} can't be found
- */
- public MySQLBooleanPrefJDBCDataModel(String dataSourceName) throws TasteException {
- this(AbstractJDBCComponent.lookupDataSource(dataSourceName),
- DEFAULT_PREFERENCE_TABLE,
- DEFAULT_USER_ID_COLUMN,
- DEFAULT_ITEM_ID_COLUMN,
- DEFAULT_PREFERENCE_TIME_COLUMN);
- }
-
- /**
- * <p>
- * Creates a {@link MySQLBooleanPrefJDBCDataModel} using the given {@link javax.sql.DataSource} and default
- * table/column names.
- * </p>
- *
- * @param dataSource
- * {@link javax.sql.DataSource} to use
- */
- public MySQLBooleanPrefJDBCDataModel(DataSource dataSource) {
- this(dataSource,
- DEFAULT_PREFERENCE_TABLE,
- DEFAULT_USER_ID_COLUMN,
- DEFAULT_ITEM_ID_COLUMN,
- DEFAULT_PREFERENCE_TIME_COLUMN);
- }
-
- /**
- * <p>
- * Creates a {@link MySQLBooleanPrefJDBCDataModel} using the given {@link javax.sql.DataSource} and default
- * table/column names.
- * </p>
- *
- * @param dataSource
- * {@link javax.sql.DataSource} to use
- * @param preferenceTable
- * name of table containing preference data
- * @param userIDColumn
- * user ID column name
- * @param itemIDColumn
- * item ID column name
- * @param timestampColumn timestamp column name (may be null)
- */
- public MySQLBooleanPrefJDBCDataModel(DataSource dataSource,
- String preferenceTable,
- String userIDColumn,
- String itemIDColumn,
- String timestampColumn) {
- super(dataSource, preferenceTable, userIDColumn, itemIDColumn,
- NO_SUCH_COLUMN,
- // getPreferenceSQL
- "SELECT 1 FROM " + preferenceTable + " WHERE " + userIDColumn + "=? AND " + itemIDColumn + "=?",
- // getPreferenceTimeSQL
- "SELECT " + timestampColumn + " FROM " + preferenceTable + " WHERE " + userIDColumn + "=? AND "
- + itemIDColumn + "=?",
- // getUserSQL
- "SELECT DISTINCT " + userIDColumn + ", " + itemIDColumn + " FROM " + preferenceTable + " WHERE "
- + userIDColumn + "=?",
- // getAllUsersSQL
- "SELECT DISTINCT " + userIDColumn + ", " + itemIDColumn + " FROM " + preferenceTable + " ORDER BY "
- + userIDColumn,
- // getNumItemsSQL
- "SELECT COUNT(DISTINCT " + itemIDColumn + ") FROM " + preferenceTable,
- // getNumUsersSQL
- "SELECT COUNT(DISTINCT " + userIDColumn + ") FROM " + preferenceTable,
- // setPreferenceSQL
- "INSERT IGNORE INTO " + preferenceTable + '(' + userIDColumn + ',' + itemIDColumn + ") VALUES (?,?)",
- // removePreference SQL
- "DELETE FROM " + preferenceTable + " WHERE " + userIDColumn + "=? AND " + itemIDColumn + "=?",
- // getUsersSQL
- "SELECT DISTINCT " + userIDColumn + " FROM " + preferenceTable + " ORDER BY " + userIDColumn,
- // getItemsSQL
- "SELECT DISTINCT " + itemIDColumn + " FROM " + preferenceTable + " ORDER BY " + itemIDColumn,
- // getPrefsForItemSQL
- "SELECT DISTINCT " + userIDColumn + ", " + itemIDColumn + " FROM " + preferenceTable + " WHERE "
- + itemIDColumn + "=? ORDER BY " + userIDColumn,
- // getNumPreferenceForItemSQL
- "SELECT COUNT(1) FROM " + preferenceTable + " WHERE " + itemIDColumn + "=?",
- // getNumPreferenceForItemsSQL
- "SELECT COUNT(1) FROM " + preferenceTable + " tp1 JOIN " + preferenceTable + " tp2 " + "USING ("
- + userIDColumn + ") WHERE tp1." + itemIDColumn + "=? and tp2." + itemIDColumn + "=?",
- // getMaxPreferenceSQL
- "SELECT 1.0",
- // getMinPreferenceSQL
- "SELECT 1.0");
- }
-
- @Override
- protected int getFetchSize() {
- // Need to return this for MySQL Connector/J to make it use streaming mode
- return Integer.MIN_VALUE;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mahout/blob/e0573de3/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModel.java
----------------------------------------------------------------------
diff --git a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModel.java b/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModel.java
deleted file mode 100644
index 9904c7e..0000000
--- a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModel.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.mahout.cf.taste.impl.model.jdbc;
-
-import javax.sql.DataSource;
-
-import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.impl.common.jdbc.AbstractJDBCComponent;
-
-/**
- * <p>
- * A {@link org.apache.mahout.cf.taste.model.JDBCDataModel} backed by a MySQL database and
- * accessed via JDBC. It may work with other JDBC databases. By default, this class
- * assumes that there is a {@link DataSource} available under the JNDI name
- * "jdbc/taste", which gives access to a database with a "taste_preferences" table with the following schema:
- * </p>
- *
- * <table>
- * <tr>
- * <th>user_id</th>
- * <th>item_id</th>
- * <th>preference</th>
- * </tr>
- * <tr>
- * <td>987</td>
- * <td>123</td>
- * <td>0.9</td>
- * </tr>
- * <tr>
- * <td>987</td>
- * <td>456</td>
- * <td>0.1</td>
- * </tr>
- * <tr>
- * <td>654</td>
- * <td>123</td>
- * <td>0.2</td>
- * </tr>
- * <tr>
- * <td>654</td>
- * <td>789</td>
- * <td>0.3</td>
- * </tr>
- * </table>
- *
- * <p>
- * {@code preference} must have a type compatible with the Java {@code float} type.
- * {@code user_id} and {@code item_id} should be compatible with long type (BIGINT). For example,
- * the following command sets up a suitable table in MySQL, complete with primary key and indexes:
- * </p>
- *
- * <p>
- *
- * <pre>
- * CREATE TABLE taste_preferences (
- * user_id BIGINT NOT NULL,
- * item_id BIGINT NOT NULL,
- * preference FLOAT NOT NULL,
- * PRIMARY KEY (user_id, item_id),
- * INDEX (user_id),
- * INDEX (item_id)
- * )
- * </pre>
- *
- * </p>
- *
- * <p>The table may optionally have a {@code timestamp} column whose type is compatible with Java
- * {@code long}.</p>
- *
- * <h3>Performance Notes</h3>
- *
- * <p>
- * See the notes in {@link AbstractJDBCDataModel} regarding using connection pooling. It's pretty vital to
- * performance.
- * </p>
- *
- * <p>
- * Some experimentation suggests that MySQL's InnoDB engine is faster than MyISAM for these kinds of
- * applications. While MyISAM is the default and, I believe, generally considered the lighter-weight and
- * faster of the two engines, my guess is the row-level locking of InnoDB helps here. Your mileage may vary.
- * </p>
- *
- * <p>
- * Here are some key settings that can be tuned for MySQL, and suggested size for a data set of around 1
- * million elements:
- * </p>
- *
- * <ul>
- * <li>innodb_buffer_pool_size=64M</li>
- * <li>myisam_sort_buffer_size=64M</li>
- * <li>query_cache_limit=64M</li>
- * <li>query_cache_min_res_unit=512K</li>
- * <li>query_cache_type=1</li>
- * <li>query_cache_size=64M</li>
- * </ul>
- *
- * <p>
- * Also consider setting some parameters on the MySQL Connector/J driver:
- * </p>
- *
- * <pre>
- * cachePreparedStatements = true
- * cachePrepStmts = true
- * cacheResultSetMetadata = true
- * alwaysSendSetIsolation = false
- * elideSetAutoCommits = true
- * </pre>
- *
- * <p>
- * Thanks to Amila Jayasooriya for contributing MySQL notes above as part of Google Summer of Code 2007.
- * </p>
- */
-public class MySQLJDBCDataModel extends AbstractJDBCDataModel {
-
- /**
- * <p>
- * Creates a {@link MySQLJDBCDataModel} using the default {@link DataSource} (named
- * {@link #DEFAULT_DATASOURCE_NAME} and default table/column names.
- * </p>
- *
- * @throws TasteException
- * if {@link DataSource} can't be found
- */
- public MySQLJDBCDataModel() throws TasteException {
- this(DEFAULT_DATASOURCE_NAME);
- }
-
- /**
- * <p>
- * Creates a {@link MySQLJDBCDataModel} using the default {@link DataSource} found under the given name, and
- * using default table/column names.
- * </p>
- *
- * @param dataSourceName
- * name of {@link DataSource} to look up
- * @throws TasteException
- * if {@link DataSource} can't be found
- */
- public MySQLJDBCDataModel(String dataSourceName) throws TasteException {
- this(AbstractJDBCComponent.lookupDataSource(dataSourceName),
- DEFAULT_PREFERENCE_TABLE,
- DEFAULT_USER_ID_COLUMN,
- DEFAULT_ITEM_ID_COLUMN,
- DEFAULT_PREFERENCE_COLUMN,
- DEFAULT_PREFERENCE_TIME_COLUMN);
- }
-
- /**
- * <p>
- * Creates a {@link MySQLJDBCDataModel} using the given {@link DataSource} and default table/column names.
- * </p>
- *
- * @param dataSource
- * {@link DataSource} to use
- */
- public MySQLJDBCDataModel(DataSource dataSource) {
- this(dataSource,
- DEFAULT_PREFERENCE_TABLE,
- DEFAULT_USER_ID_COLUMN,
- DEFAULT_ITEM_ID_COLUMN,
- DEFAULT_PREFERENCE_COLUMN,
- DEFAULT_PREFERENCE_TIME_COLUMN);
- }
-
- /**
- * <p>
- * Creates a {@link MySQLJDBCDataModel} using the given {@link DataSource} and default table/column names.
- * </p>
- *
- * @param dataSource
- * {@link DataSource} to use
- * @param preferenceTable
- * name of table containing preference data
- * @param userIDColumn
- * user ID column name
- * @param itemIDColumn
- * item ID column name
- * @param preferenceColumn
- * preference column name
- * @param timestampColumn timestamp column name (may be null)
- */
- public MySQLJDBCDataModel(DataSource dataSource,
- String preferenceTable,
- String userIDColumn,
- String itemIDColumn,
- String preferenceColumn,
- String timestampColumn) {
- super(dataSource, preferenceTable, userIDColumn, itemIDColumn, preferenceColumn,
- // getPreferenceSQL
- "SELECT " + preferenceColumn + " FROM " + preferenceTable + " WHERE " + userIDColumn + "=? AND "
- + itemIDColumn + "=?",
- // getPreferenceTimeSQL
- "SELECT " + timestampColumn + " FROM " + preferenceTable + " WHERE " + userIDColumn + "=? AND "
- + itemIDColumn + "=?",
- // getUserSQL
- "SELECT DISTINCT " + userIDColumn + ", " + itemIDColumn + ", " + preferenceColumn + " FROM " + preferenceTable
- + " WHERE " + userIDColumn + "=? ORDER BY " + itemIDColumn,
- // getAllUsersSQL
- "SELECT DISTINCT " + userIDColumn + ", " + itemIDColumn + ", " + preferenceColumn + " FROM " + preferenceTable
- + " ORDER BY " + userIDColumn + ", " + itemIDColumn,
- // getNumItemsSQL
- "SELECT COUNT(DISTINCT " + itemIDColumn + ") FROM " + preferenceTable,
- // getNumUsersSQL
- "SELECT COUNT(DISTINCT " + userIDColumn + ") FROM " + preferenceTable,
- // setPreferenceSQL
- "INSERT INTO " + preferenceTable + '(' + userIDColumn + ',' + itemIDColumn + ',' + preferenceColumn
- + ") VALUES (?,?,?) ON DUPLICATE KEY UPDATE " + preferenceColumn + "=?",
- // removePreference SQL
- "DELETE FROM " + preferenceTable + " WHERE " + userIDColumn + "=? AND " + itemIDColumn + "=?",
- // getUsersSQL
- "SELECT DISTINCT " + userIDColumn + " FROM " + preferenceTable + " ORDER BY " + userIDColumn,
- // getItemsSQL
- "SELECT DISTINCT " + itemIDColumn + " FROM " + preferenceTable + " ORDER BY " + itemIDColumn,
- // getPrefsForItemSQL
- "SELECT DISTINCT " + userIDColumn + ", " + itemIDColumn + ", " + preferenceColumn + " FROM " + preferenceTable
- + " WHERE " + itemIDColumn + "=? ORDER BY " + userIDColumn,
- // getNumPreferenceForItemSQL
- "SELECT COUNT(1) FROM " + preferenceTable + " WHERE " + itemIDColumn + "=?",
- // getNumPreferenceForItemsSQL
- "SELECT COUNT(1) FROM " + preferenceTable + " tp1 JOIN " + preferenceTable + " tp2 " + "USING ("
- + userIDColumn + ") WHERE tp1." + itemIDColumn + "=? and tp2." + itemIDColumn + "=?",
- "SELECT MAX(" + preferenceColumn + ") FROM " + preferenceTable,
- "SELECT MIN(" + preferenceColumn + ") FROM " + preferenceTable);
- }
-
- @Override
- protected int getFetchSize() {
- // Need to return this for MySQL Connector/J to make it use streaming mode
- return Integer.MIN_VALUE;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mahout/blob/e0573de3/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/PostgreSQLBooleanPrefJDBCDataModel.java
----------------------------------------------------------------------
diff --git a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/PostgreSQLBooleanPrefJDBCDataModel.java b/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/PostgreSQLBooleanPrefJDBCDataModel.java
deleted file mode 100644
index 6dda281..0000000
--- a/integration/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/PostgreSQLBooleanPrefJDBCDataModel.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.mahout.cf.taste.impl.model.jdbc;
-
-import com.google.common.base.Preconditions;
-import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.common.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.sql.DataSource;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-
-/**
- * <p>
- * See also {@link org.apache.mahout.cf.taste.impl.model.jdbc.PostgreSQLJDBCDataModel} --
- * same except deals with a table without preference info:
- * </p>
- *
- * <p>
- *
- * <pre>
- * CREATE TABLE taste_preferences (
- * user_id BIGINT NOT NULL,
- * item_id BIGINT NOT NULL,
- * PRIMARY KEY (user_id, item_id)
- * );
- * CREATE INDEX taste_preferences_user_id_index ON taste_preferences (user_id);
- * CREATE INDEX taste_preferences_item_id_index ON taste_preferences (item_id);
- * </pre>
- *
- * </p>
- *
- * @see PostgreSQLJDBCDataModel
- */
-public class PostgreSQLBooleanPrefJDBCDataModel extends SQL92BooleanPrefJDBCDataModel {
-
- private static final Logger log = LoggerFactory.getLogger(PostgreSQLBooleanPrefJDBCDataModel.class);
-
- private static final String POSTGRESQL_DUPLICATE_KEY_STATE = "23505"; // this is brittle...
-
- /**
- * <p>
- * Creates a using the default {@link javax.sql.DataSource} (named
- * {@link #DEFAULT_DATASOURCE_NAME} and default table/column names.
- * </p>
- *
- * @throws org.apache.mahout.cf.taste.common.TasteException
- * if {@link javax.sql.DataSource} can't be found
- */
- public PostgreSQLBooleanPrefJDBCDataModel() throws TasteException {
- }
-
- /**
- * <p>
- * Creates a using the default {@link javax.sql.DataSource} found
- * under the given name, and using default table/column names.
- * </p>
- *
- * @param dataSourceName name of {@link javax.sql.DataSource} to look up
- * @throws org.apache.mahout.cf.taste.common.TasteException
- * if {@link javax.sql.DataSource} can't be found
- */
- public PostgreSQLBooleanPrefJDBCDataModel(String dataSourceName) throws TasteException {
- super(dataSourceName);
- }
-
- /**
- * <p>
- * Creates a using the given {@link javax.sql.DataSource} and default
- * table/column names.
- * </p>
- *
- * @param dataSource {@link javax.sql.DataSource} to use
- */
- public PostgreSQLBooleanPrefJDBCDataModel(DataSource dataSource) {
- super(dataSource);
- }
-
- /**
- * <p>
- * Creates a using the given {@link javax.sql.DataSource} and default
- * table/column names.
- * </p>
- *
- * @param dataSource {@link javax.sql.DataSource} to use
- * @param preferenceTable name of table containing preference data
- * @param userIDColumn user ID column name
- * @param itemIDColumn item ID column name
- * @param timestampColumn timestamp column name (may be null)
- */
- public PostgreSQLBooleanPrefJDBCDataModel(DataSource dataSource,
- String preferenceTable,
- String userIDColumn,
- String itemIDColumn,
- String timestampColumn) {
- super(dataSource, preferenceTable, userIDColumn, itemIDColumn, timestampColumn);
- }
-
- /**
- * Override since PostgreSQL doesn't have the same non-standard capability that MySQL has, to optionally
- * ignore an insert that fails since the row exists already.
- */
- @Override
- public void setPreference(long userID, long itemID, float value) throws TasteException {
- Preconditions.checkArgument(!Float.isNaN(value), "NaN value");
- log.debug("Setting preference for user {}, item {}", userID, itemID);
-
- String setPreferenceSQL = getSetPreferenceSQL();
- Connection conn = null;
- PreparedStatement stmt = null;
- try {
- conn = getDataSource().getConnection();
- stmt = conn.prepareStatement(setPreferenceSQL);
- setLongParameter(stmt, 1, userID);
- setLongParameter(stmt, 2, itemID);
- log.debug("Executing SQL update: {}", setPreferenceSQL);
- stmt.executeUpdate();
- } catch (SQLException sqle) {
- if (!POSTGRESQL_DUPLICATE_KEY_STATE.equals(sqle.getSQLState())) {
- log.warn("Exception while setting preference", sqle);
- throw new TasteException(sqle);
- }
- } finally {
- IOUtils.quietClose(null, stmt, conn);
- }
- }
-
-}