mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-18 07:23:08 +00:00
indexAll method uses ItemIterator and returns number of Items indexed
Add getNormalizedTitle method Implementation cleanups: + getTotalInIndex method returns the number of Items in a Browse index. previously this functionality was clumped together in the getSomethingInternal() method + getTargetColumns() returns the correct columns for a browse type + getSubqueryClause() does what its name says + getItemId() ditto + addScopeClause() puts all the scoping logic in one place Added examples of generated SQL to javadoc Remove unused main method from NormalizedTitle class Resource cleanups in BrowseCache class git-svn-id: http://scm.dspace.org/svn/repo/trunk@111 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
@@ -328,22 +328,25 @@ public class Browse
|
|||||||
* Index all items in DSpace. This method may be resource-intensive.
|
* Index all items in DSpace. This method may be resource-intensive.
|
||||||
*
|
*
|
||||||
* @param context - The database context
|
* @param context - The database context
|
||||||
|
* @return - The number of items indexed.
|
||||||
* @exception SQLException - If a database error occurs
|
* @exception SQLException - If a database error occurs
|
||||||
*/
|
*/
|
||||||
public static void indexAll(Context context)
|
public static int indexAll(Context context)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
indexRemoveAll(context);
|
indexRemoveAll(context);
|
||||||
|
|
||||||
TableRowIterator iterator = DatabaseManager.query(context, null, "select item_id from Item");
|
int count = 0;
|
||||||
|
ItemIterator iterator = Item.findAll(context);
|
||||||
|
|
||||||
while (iterator.hasNext())
|
while (iterator.hasNext())
|
||||||
{
|
{
|
||||||
TableRow row = (TableRow) iterator.next();
|
itemAdded(context, (Item) iterator.next());
|
||||||
Item item = Item.find(context, row.getIntColumn("item_id"));
|
count++;
|
||||||
itemAdded(context, item);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all items in DSpace from the Browse index.
|
* Remove all items in DSpace from the Browse index.
|
||||||
@@ -362,6 +365,14 @@ public class Browse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
// Other methods
|
||||||
|
////////////////////////////////////////
|
||||||
|
public static String getNormalizedTitle(String title, String lang)
|
||||||
|
{
|
||||||
|
return NormalizedTitle.normalize(title, lang);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
// Private methods
|
// Private methods
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
@@ -394,10 +405,8 @@ public class Browse
|
|||||||
////////////////////
|
////////////////////
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
////////////////////
|
////////////////////
|
||||||
// No null collections
|
|
||||||
if ((scopeType == COLLECTION_SCOPE) && (obj == null))
|
if ((scopeType == COLLECTION_SCOPE) && (obj == null))
|
||||||
throw new IllegalArgumentException("Collection is null");
|
throw new IllegalArgumentException("Collection is null");
|
||||||
// No null communities
|
|
||||||
if ((scopeType == COMMUNITY_SCOPE) && (obj == null))
|
if ((scopeType == COMMUNITY_SCOPE) && (obj == null))
|
||||||
throw new IllegalArgumentException("Community is null");
|
throw new IllegalArgumentException("Community is null");
|
||||||
|
|
||||||
@@ -410,7 +419,10 @@ public class Browse
|
|||||||
BrowseInfo cachedInfo = (BrowseInfo) BrowseCache.get(key);
|
BrowseInfo cachedInfo = (BrowseInfo) BrowseCache.get(key);
|
||||||
|
|
||||||
if (cachedInfo != null)
|
if (cachedInfo != null)
|
||||||
|
{
|
||||||
|
cachedInfo.setCached(true);
|
||||||
return cachedInfo;
|
return cachedInfo;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
// Convenience booleans
|
// Convenience booleans
|
||||||
@@ -420,8 +432,7 @@ public class Browse
|
|||||||
boolean valueIsItem = (value instanceof Item);
|
boolean valueIsItem = (value instanceof Item);
|
||||||
boolean valueIsInteger = (value instanceof Integer);
|
boolean valueIsInteger = (value instanceof Integer);
|
||||||
// True if we want to search from the start
|
// True if we want to search from the start
|
||||||
// This is true when:
|
// This is true when the client passed a null value
|
||||||
// the client passed a null value
|
|
||||||
boolean searchFromStart = (value == null);
|
boolean searchFromStart = (value == null);
|
||||||
// True if we want ALL values
|
// True if we want ALL values
|
||||||
boolean nolimit = (total == -1);
|
boolean nolimit = (total == -1);
|
||||||
@@ -450,16 +461,6 @@ public class Browse
|
|||||||
// See http://www.postgresql.org/idocs/index.php?xact-serializable.html
|
// See http://www.postgresql.org/idocs/index.php?xact-serializable.html
|
||||||
//
|
//
|
||||||
// Performance hit unknown...
|
// Performance hit unknown...
|
||||||
|
|
||||||
boolean autocommit = connection.getAutoCommit();
|
|
||||||
|
|
||||||
if (!autocommit)
|
|
||||||
{
|
|
||||||
if (log.isInfoEnabled())
|
|
||||||
log.info("Browse: Autocommit is false");
|
|
||||||
}
|
|
||||||
connection.setAutoCommit(false);
|
|
||||||
|
|
||||||
int transactionIsolation = connection.getTransactionIsolation();
|
int transactionIsolation = connection.getTransactionIsolation();
|
||||||
|
|
||||||
connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
|
connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
|
||||||
@@ -471,7 +472,9 @@ public class Browse
|
|||||||
////////////////////
|
////////////////////
|
||||||
// Run a subquery, if necessary
|
// Run a subquery, if necessary
|
||||||
String subqueryValue = needsSubquery ?
|
String subqueryValue = needsSubquery ?
|
||||||
doSubquery(connection, obj, scopeType, browseType, value) : null;
|
doSubquery(connection, obj,
|
||||||
|
scopeType, browseType,
|
||||||
|
getItemId(value)) : null;
|
||||||
|
|
||||||
if (needsSubquery && log.isInfoEnabled())
|
if (needsSubquery && log.isInfoEnabled())
|
||||||
log.info("Got subquery value: \"" + subqueryValue + "\"");
|
log.info("Got subquery value: \"" + subqueryValue + "\"");
|
||||||
@@ -483,8 +486,8 @@ public class Browse
|
|||||||
if (log.isInfoEnabled())
|
if (log.isInfoEnabled())
|
||||||
log.info("Created sql: \"" + sql + "\"");
|
log.info("Created sql: \"" + sql + "\"");
|
||||||
|
|
||||||
// Loop through twice -- once to get items _before_ the value,
|
// Loop through twice -- once to get items _before_ the value,
|
||||||
// and once for those after.
|
// and once for those after.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
List theResults = new ArrayList();
|
List theResults = new ArrayList();
|
||||||
@@ -509,7 +512,7 @@ public class Browse
|
|||||||
if ((!before) && (total == 0))
|
if ((!before) && (total == 0))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Format the SQL
|
// Format the SQL
|
||||||
String SQL = formatSql(sql,
|
String SQL = formatSql(sql,
|
||||||
browseType,
|
browseType,
|
||||||
before ? numberBefore : total,
|
before ? numberBefore : total,
|
||||||
@@ -522,7 +525,7 @@ public class Browse
|
|||||||
log.info("Formatted " + (before ? "before" : "after") +
|
log.info("Formatted " + (before ? "before" : "after") +
|
||||||
" sql: \"" + SQL + "\"");
|
" sql: \"" + SQL + "\"");
|
||||||
|
|
||||||
// Create a PreparedStatement
|
// Create a PreparedStatement
|
||||||
statement = connection.prepareStatement(SQL);
|
statement = connection.prepareStatement(SQL);
|
||||||
|
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
@@ -531,8 +534,7 @@ public class Browse
|
|||||||
String bindValue = ((!searchFromStart) && needsSubquery) ?
|
String bindValue = ((!searchFromStart) && needsSubquery) ?
|
||||||
subqueryValue : (String) value;
|
subqueryValue : (String) value;
|
||||||
|
|
||||||
bindParameters(statement, bindValue, searchFromStart, needsSubquery,
|
bindParameters(statement, bindValue, searchFromStart, needsSubquery);
|
||||||
false);
|
|
||||||
|
|
||||||
// Run a query, get results
|
// Run a query, get results
|
||||||
String table = BrowseTables.getTable(scopeType, browseType);
|
String table = BrowseTables.getTable(scopeType, browseType);
|
||||||
@@ -586,29 +588,7 @@ public class Browse
|
|||||||
|
|
||||||
int resultSize = theResults.size();
|
int resultSize = theResults.size();
|
||||||
|
|
||||||
//////////////////////////////
|
int theTotal = getTotalInIndex(obj, scopeType, browseType, connection, value, total, resultSize);
|
||||||
// Counting
|
|
||||||
//////////////////////////////
|
|
||||||
boolean countTotal = true;
|
|
||||||
int theTotal = 0;
|
|
||||||
|
|
||||||
// Got less authors than requested
|
|
||||||
// This means that we do not need to count them
|
|
||||||
if ((browseType == ITEMS_BY_AUTHOR_BROWSE) && (total > resultSize))
|
|
||||||
{
|
|
||||||
countTotal = false;
|
|
||||||
theTotal = resultSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (countTotal)
|
|
||||||
{
|
|
||||||
statement = createTotalSql(obj, scopeType, browseType, connection, value);
|
|
||||||
|
|
||||||
theTotal = getIntValue(statement);
|
|
||||||
|
|
||||||
// Cleanup the statement
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// OK, we've counted everything.
|
// OK, we've counted everything.
|
||||||
// Now figure out how many things match the specific query.
|
// Now figure out how many things match the specific query.
|
||||||
@@ -657,7 +637,7 @@ public class Browse
|
|||||||
//////////
|
//////////
|
||||||
String svalue = valueIsString ? (String) value : subqueryValue;
|
String svalue = valueIsString ? (String) value : subqueryValue;
|
||||||
|
|
||||||
bindParameters(statement, svalue, searchFromStart, needsSubquery, true);
|
bindParameters(statement, svalue, searchFromStart, needsSubquery);
|
||||||
|
|
||||||
//////////
|
//////////
|
||||||
// Run the query, extract results
|
// Run the query, extract results
|
||||||
@@ -679,37 +659,12 @@ public class Browse
|
|||||||
statement.close();
|
statement.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log.isInfoEnabled())
|
// FIXME -- sorting is busted
|
||||||
{
|
BrowseInfo info = new BrowseInfo
|
||||||
log.info("Number of Results: " + theResults.size() +
|
(theResults, overallPosition,
|
||||||
" Overall position: " + overallPosition +
|
theTotal, offset);
|
||||||
" Total " + theTotal +
|
|
||||||
" Offset " + offset);
|
|
||||||
int lastIndex = (overallPosition + resultSize);
|
|
||||||
boolean noresults = (theTotal == 0) || (resultSize == 0);
|
|
||||||
|
|
||||||
log.info("Got results: " +
|
logInfo(info);
|
||||||
(noresults ? 0 : overallPosition) +
|
|
||||||
" to " +
|
|
||||||
(noresults ? 0 : lastIndex) +
|
|
||||||
" out of " + theTotal);
|
|
||||||
}
|
|
||||||
|
|
||||||
BrowseInfo info = null;
|
|
||||||
if (sort == null)
|
|
||||||
{
|
|
||||||
info = new BrowseInfo(theResults, overallPosition, theTotal, offset);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
String element = sort.booleanValue() ? "title" : "date";
|
|
||||||
String qualifier = sort.booleanValue() ? null : "issued";
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
info = new BrowseInfo
|
|
||||||
(theResults, overallPosition,
|
|
||||||
theTotal, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
BrowseCache.add(key, info);
|
BrowseCache.add(key, info);
|
||||||
return info;
|
return info;
|
||||||
@@ -729,8 +684,7 @@ public class Browse
|
|||||||
// Need to do this because "closing" the connection simply
|
// Need to do this because "closing" the connection simply
|
||||||
// returns it to the pool
|
// returns it to the pool
|
||||||
connection.setTransactionIsolation(transactionIsolation);
|
connection.setTransactionIsolation(transactionIsolation);
|
||||||
connection.setAutoCommit(autocommit);
|
// connection.close();
|
||||||
connection.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -750,48 +704,13 @@ public class Browse
|
|||||||
)
|
)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
////////////////////
|
|
||||||
// Table and column
|
|
||||||
////////////////////
|
|
||||||
String tablename = BrowseTables.getTable(scope, browseType);
|
String tablename = BrowseTables.getTable(scope, browseType);
|
||||||
String column = BrowseTables.getValueColumn(browseType);
|
String column = BrowseTables.getValueColumn(browseType);
|
||||||
|
|
||||||
////////////////////
|
StringBuffer sqlb = new StringBuffer()
|
||||||
// Convenience booleans
|
|
||||||
////////////////////
|
|
||||||
// True if the value is....
|
|
||||||
boolean valueIsString = (value instanceof String);
|
|
||||||
boolean valueIsItem = (value instanceof Item);
|
|
||||||
boolean valueIsInteger = (value instanceof Integer);
|
|
||||||
// True if we want to search from the start
|
|
||||||
// boolean searchFromStart = (value == null) && (! valueIsInteger) && (! valueIsInteger);
|
|
||||||
boolean searchFromStart = (value == null);
|
|
||||||
// True if we want ALL values
|
|
||||||
boolean nolimit = (total == -1);
|
|
||||||
// True if we added a where clause
|
|
||||||
boolean addedWhereClause = false;
|
|
||||||
// True if we need a subquery
|
|
||||||
boolean needsSubquery = valueIsInteger || valueIsItem;
|
|
||||||
|
|
||||||
////////////////////
|
|
||||||
// Ids
|
|
||||||
////////////////////
|
|
||||||
int communityId = (obj instanceof Community) ? ((Community) obj).getID() : -1;
|
|
||||||
int collectionId = (obj instanceof Collection) ? ((Collection) obj).getID() : -1;
|
|
||||||
int item_id = -1;
|
|
||||||
|
|
||||||
if (valueIsInteger)
|
|
||||||
item_id = ((Integer) value).intValue();
|
|
||||||
else if (valueIsItem)
|
|
||||||
item_id = ((Item) value).getID();
|
|
||||||
|
|
||||||
// Target columns are either just authors or everything
|
|
||||||
String targetColumns = (browseType == AUTHORS_BROWSE) ? "distinct author" : "*";
|
|
||||||
|
|
||||||
StringBuffer sqlb = new StringBuffer()// Column(s) to select
|
|
||||||
.append("select ")
|
.append("select ")
|
||||||
.append(isCount ? "count(" : "")
|
.append(isCount ? "count(" : "")
|
||||||
.append(targetColumns)
|
.append(getTargetColumns(browseType))
|
||||||
.append(isCount ? ")" : "")
|
.append(isCount ? ")" : "")
|
||||||
.append(" from ")
|
.append(" from ")
|
||||||
.append(tablename);
|
.append(tablename);
|
||||||
@@ -801,26 +720,19 @@ public class Browse
|
|||||||
// We use a separate query to make sure the subquery works correctly
|
// We use a separate query to make sure the subquery works correctly
|
||||||
// when item values are the same. (this is transactionally
|
// when item values are the same. (this is transactionally
|
||||||
// safe because we set the isolation level).
|
// safe because we set the isolation level).
|
||||||
String subquery = null;
|
|
||||||
|
|
||||||
if (subqueryValue != null)
|
// If we're NOT searching from the start, add some clauses
|
||||||
|
boolean addedWhereClause = false;
|
||||||
|
if (value != null)
|
||||||
{
|
{
|
||||||
subquery = new StringBuffer()
|
boolean needsSubquery = (value instanceof Integer) ||
|
||||||
.append(" or ( ")
|
(value instanceof Item);
|
||||||
.append(column)
|
String subquery = (subqueryValue == null ? null :
|
||||||
// Item id must be before or after the desired item
|
getSubqueryClause(column, getItemId(value)));
|
||||||
.append(" = ? and item_id {0} ")
|
|
||||||
.append(item_id)
|
|
||||||
.append(")")
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log.isDebugEnabled())
|
if (log.isDebugEnabled())
|
||||||
log.debug("Subquery is \"" + subquery + "\"");
|
log.debug("Subquery is \"" + subquery + "\"");
|
||||||
|
|
||||||
// If we're NOT searching from the start, add some clauses
|
|
||||||
if (!searchFromStart)
|
|
||||||
{
|
|
||||||
sqlb
|
sqlb
|
||||||
.append(" where ")
|
.append(" where ")
|
||||||
.append("(")
|
.append("(")
|
||||||
@@ -834,79 +746,100 @@ public class Browse
|
|||||||
addedWhereClause = true;
|
addedWhereClause = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optionally, add a scope clause
|
addScopeClause(sqlb, scope, obj,
|
||||||
if (scope == COLLECTION_SCOPE)
|
addedWhereClause ? " and " : " where ");
|
||||||
sqlb.append(addedWhereClause ? " and " : " where ").append(" collection_id = ").append(collectionId);
|
|
||||||
else if (scope == COMMUNITY_SCOPE)
|
|
||||||
sqlb.append(addedWhereClause ? " and " : " where ").append(" community_id = ").append(communityId);
|
|
||||||
|
|
||||||
// No more clauses after this (except maybe Santa Claus).....
|
// For counting, skip the "order by" and "limit" clauses
|
||||||
|
|
||||||
// For counting, skip the "order by" and "limit" clauses
|
|
||||||
if (isCount)
|
if (isCount)
|
||||||
return sqlb.toString();
|
return sqlb.toString();
|
||||||
|
|
||||||
// Add an order by clause -- a parameter
|
// Add an order by clause -- a parameter
|
||||||
sqlb.append(" order by ").append(column).append("{2}")
|
sqlb.append(" order by ").append(column).append("{2}")
|
||||||
// If an item, make sure it's ordered by item_id as well
|
// If an item, make sure it's ordered by item_id as well
|
||||||
.append((valueIsString || (browseType == AUTHORS_BROWSE))
|
.append(((value instanceof String) || (browseType == AUTHORS_BROWSE))
|
||||||
? "" : ", item_id");
|
? "" : ", item_id");
|
||||||
|
|
||||||
// A limit on the total returned (Postgres extension)
|
// A limit on the total returned (Postgres extension)
|
||||||
// This is a parameter
|
// This is a parameter
|
||||||
if (!nolimit)
|
if (total != -1)
|
||||||
sqlb.append(" LIMIT {3} ");
|
sqlb.append(" LIMIT {3} ");
|
||||||
|
|
||||||
return sqlb.toString();
|
return sqlb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a PreparedStatement which counts the total objects in an index.
|
* Return the total number of values in an index.
|
||||||
|
* Although this may look a bit dizzying, the basic idea is
|
||||||
|
* straightforward:
|
||||||
|
*
|
||||||
|
* We total Authors with SQL like:
|
||||||
|
* select count(distinct author) from ItemsByAuthor;
|
||||||
|
* ItemsByAuthor with:
|
||||||
|
* select count(*) from ItemsByAuthor where author = ?;
|
||||||
|
* and every other index with:
|
||||||
|
* select count(*) from ItemsByTitle;
|
||||||
|
*
|
||||||
|
* If limiting to a community or collection, we add a clause like:
|
||||||
|
* community_id = 7
|
||||||
|
* collection_id = 201
|
||||||
*/
|
*/
|
||||||
private static PreparedStatement createTotalSql(Object obj,
|
private static int getTotalInIndex(Object obj,
|
||||||
int scope,
|
int scopeType,
|
||||||
int browseType,
|
int browseType,
|
||||||
Connection connection,
|
Connection connection,
|
||||||
Object value
|
Object value,
|
||||||
)
|
int total,
|
||||||
|
int resultSize)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
// For counting the total, we need to know:
|
if ((browseType == ITEMS_BY_AUTHOR_BROWSE) && (total > resultSize))
|
||||||
// whether browseType is ITEMS_BY_AUTHOR_BROWSE. In this case, we'll
|
return resultSize;
|
||||||
// request different columns.
|
|
||||||
// scope is COLLECTION_SCOPE or COMMUNITY_SCOPE. If it is, we'll
|
|
||||||
// append a clause specifying the id.
|
|
||||||
|
|
||||||
boolean needsWhere = (browseType == ITEMS_BY_AUTHOR_BROWSE) ||
|
PreparedStatement statement = null;
|
||||||
(scope == COLLECTION_SCOPE) || (scope == COMMUNITY_SCOPE);
|
|
||||||
boolean needsAnd = (browseType == ITEMS_BY_AUTHOR_BROWSE) &&
|
|
||||||
((scope == COLLECTION_SCOPE) || (scope == COMMUNITY_SCOPE));
|
|
||||||
|
|
||||||
////////////////////
|
try
|
||||||
// Ids
|
{
|
||||||
////////////////////
|
String table = BrowseTables.getTable(scopeType, browseType);
|
||||||
int communityId = (obj instanceof Community) ? ((Community) obj).getID() : -1;
|
|
||||||
int collectionId = (obj instanceof Collection) ? ((Collection) obj).getID() : -1;
|
|
||||||
|
|
||||||
String table = BrowseTables.getTable(scope, browseType);
|
StringBuffer buffer = new StringBuffer()
|
||||||
|
.append("select count(")
|
||||||
|
.append(getTargetColumns(browseType))
|
||||||
|
.append(") from ")
|
||||||
|
.append(table);
|
||||||
|
|
||||||
String sql = new StringBuffer().append("select count(").append((browseType == AUTHORS_BROWSE) ? "distinct author" : "*").append(") from ").append(table).append(needsWhere ? " where " : "").append((browseType == ITEMS_BY_AUTHOR_BROWSE) ? " author = ?" : "").append(needsAnd ? " and " : "")// Optionally, add a scope clause
|
boolean hasWhere = false;
|
||||||
.append((scope == COLLECTION_SCOPE) ? " collection_id = " : "").append((scope == COLLECTION_SCOPE) ? Integer.toString(collectionId) : "").append((scope == COMMUNITY_SCOPE) ? " community_id = " : "").append((scope == COMMUNITY_SCOPE) ? Integer.toString(communityId) : "").toString();
|
if (browseType == ITEMS_BY_AUTHOR_BROWSE)
|
||||||
|
{
|
||||||
|
hasWhere = true;
|
||||||
|
buffer.append(" where author = ?");
|
||||||
|
}
|
||||||
|
|
||||||
if (log.isInfoEnabled())
|
String sql = addScopeClause(buffer, scopeType, obj,
|
||||||
log.info("Total sql: \"" + sql + "\"");
|
hasWhere ? "and" : "where")
|
||||||
|
.toString();
|
||||||
|
|
||||||
PreparedStatement statement = connection.prepareStatement(sql);
|
if (log.isInfoEnabled())
|
||||||
|
log.info("Total sql: \"" + sql + "\"");
|
||||||
|
|
||||||
// Bind the author value, if necessary
|
statement = connection.prepareStatement(sql);
|
||||||
if (browseType == ITEMS_BY_AUTHOR_BROWSE)
|
|
||||||
statement.setString(1, (String) value);
|
|
||||||
|
|
||||||
return statement;
|
if (browseType == ITEMS_BY_AUTHOR_BROWSE)
|
||||||
|
statement.setString(1, (String) value);
|
||||||
|
|
||||||
|
return getIntValue(statement);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (statement != null)
|
||||||
|
statement.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format the SQL string according to BROWSETYPE.
|
* Format SQL according to BROWSETYPE.
|
||||||
|
*
|
||||||
|
* The different browses use different operators.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
private static String formatSql(String sql,
|
private static String formatSql(String sql,
|
||||||
int browseType,
|
int browseType,
|
||||||
@@ -923,8 +856,8 @@ public class Browse
|
|||||||
// For authors, only equality is relevant
|
// For authors, only equality is relevant
|
||||||
if (browseType == ITEMS_BY_AUTHOR_BROWSE)
|
if (browseType == ITEMS_BY_AUTHOR_BROWSE)
|
||||||
afterOperator = "=";
|
afterOperator = "=";
|
||||||
// Subqueries add a clause which checks for the item specifically,
|
// Subqueries add a clause which checks for the item specifically,
|
||||||
// so we do not check for equality here
|
// so we do not check for equality here
|
||||||
if (subqueryValue != null)
|
if (subqueryValue != null)
|
||||||
{
|
{
|
||||||
beforeOperator = "<";
|
beforeOperator = "<";
|
||||||
@@ -953,9 +886,9 @@ public class Browse
|
|||||||
if (!ascending)
|
if (!ascending)
|
||||||
order = before ? "" : " desc";
|
order = before ? "" : " desc";
|
||||||
|
|
||||||
// Note that it's OK to have unused arguments in the array;
|
// Note that it's OK to have unused arguments in the array;
|
||||||
// see the javadoc of java.text.MessageFormat
|
// see the javadoc of java.text.MessageFormat
|
||||||
// for the whole story.
|
// for the whole story.
|
||||||
List args = new ArrayList();
|
List args = new ArrayList();
|
||||||
|
|
||||||
args.add(before ? beforeSubqueryOperator : afterSubqueryOperator);
|
args.add(before ? beforeSubqueryOperator : afterSubqueryOperator);
|
||||||
@@ -970,93 +903,183 @@ public class Browse
|
|||||||
* Bind PreparedStatement parameters
|
* Bind PreparedStatement parameters
|
||||||
*/
|
*/
|
||||||
private static void bindParameters(PreparedStatement statement,
|
private static void bindParameters(PreparedStatement statement,
|
||||||
String value,
|
String value,
|
||||||
boolean searchFromStart,
|
boolean searchFromStart,
|
||||||
boolean needsSubquery,
|
boolean needsSubquery
|
||||||
boolean isCount
|
|
||||||
)
|
)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
if (!searchFromStart)
|
if (searchFromStart)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (needsSubquery)
|
||||||
{
|
{
|
||||||
if (needsSubquery)
|
if (log.isDebugEnabled())
|
||||||
{
|
log.debug("Binding subquery value \"" + value + "\"");
|
||||||
if (log.isDebugEnabled())
|
|
||||||
log.debug("Binding subquery value \"" + value + "\"");
|
|
||||||
|
|
||||||
statement.setString(1, value);
|
statement.setString(1, value);
|
||||||
statement.setString(2, value);
|
statement.setString(2, value);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (log.isDebugEnabled())
|
|
||||||
log.debug("Binding value \"" + value + "\"");
|
|
||||||
|
|
||||||
statement.setString(1, (String) value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
private static String doSubquery(Connection connection,
|
|
||||||
Object obj,
|
|
||||||
int scope,
|
|
||||||
int browseType,
|
|
||||||
Object value
|
|
||||||
)
|
|
||||||
throws SQLException
|
|
||||||
{
|
|
||||||
PreparedStatement statement = null;
|
|
||||||
|
|
||||||
String tablename = BrowseTables.getTable(scope, browseType);
|
|
||||||
String column = BrowseTables.getValueColumn(browseType);
|
|
||||||
|
|
||||||
////////////////////
|
|
||||||
// Ids
|
|
||||||
////////////////////
|
|
||||||
int communityId = (obj instanceof Community) ? ((Community) obj).getID() : -1;
|
|
||||||
int collectionId = (obj instanceof Collection) ? ((Collection) obj).getID() : -1;
|
|
||||||
int item_id = -1;
|
|
||||||
|
|
||||||
if (value instanceof Integer)
|
|
||||||
item_id = ((Integer) value).intValue();
|
|
||||||
else if (value instanceof Item)
|
|
||||||
item_id = ((Item) value).getID();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
String itemValueQuery = new StringBuffer().append("select ").append("max(").append(column).append(") from ").append(tablename).append(" where ").append(" item_id = ").append(item_id).append((scope == COLLECTION_SCOPE) ? " and collection_id = " : "").append((scope == COLLECTION_SCOPE) ? Integer.toString(collectionId) : "").append((scope == COMMUNITY_SCOPE) ? " and community_id = " : "").append((scope == COMMUNITY_SCOPE) ? Integer.toString(communityId) : "").toString();
|
if (log.isDebugEnabled())
|
||||||
|
log.debug("Binding value \"" + value + "\"");
|
||||||
|
|
||||||
// Run the query
|
statement.setString(1, (String) value);
|
||||||
statement = connection.prepareStatement(itemValueQuery);
|
|
||||||
return getStringValue(statement);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (statement != null)
|
|
||||||
statement.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a single String value from STATEMENT.
|
* Run a query to find a browse index value for item_id.
|
||||||
|
*
|
||||||
|
* In general, these queries look like this:
|
||||||
|
* select max(date_issued) from ItemsByDate where item_id = 7;
|
||||||
|
*
|
||||||
|
* The max operator ensures that only one value is returned.
|
||||||
|
*
|
||||||
|
* If limiting to a community or collection, we add a clause like:
|
||||||
|
* community_id = 7
|
||||||
|
* collection_id = 201
|
||||||
*/
|
*/
|
||||||
private static String getStringValue(PreparedStatement statement)
|
private static String doSubquery(Connection connection,
|
||||||
|
Object obj,
|
||||||
|
int scope,
|
||||||
|
int browseType,
|
||||||
|
int item_id
|
||||||
|
)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
|
PreparedStatement statement = null;
|
||||||
ResultSet results = null;
|
ResultSet results = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
String tablename = BrowseTables.getTable(scope, browseType);
|
||||||
|
String column = BrowseTables.getValueColumn(browseType);
|
||||||
|
|
||||||
|
StringBuffer buffer = new StringBuffer()
|
||||||
|
.append("select ")
|
||||||
|
.append("max(")
|
||||||
|
.append(column)
|
||||||
|
.append(") from ")
|
||||||
|
.append(tablename)
|
||||||
|
.append(" where ")
|
||||||
|
.append(" item_id = ")
|
||||||
|
.append(item_id);
|
||||||
|
|
||||||
|
String itemValueQuery = addScopeClause(buffer, scope, obj, "and")
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
statement = connection.prepareStatement(itemValueQuery);
|
||||||
results = statement.executeQuery();
|
results = statement.executeQuery();
|
||||||
return results.next() ? results.getString(1) : null;
|
return results.next() ? results.getString(1) : null;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
if (statement != null)
|
||||||
|
statement.close();
|
||||||
if (results != null)
|
if (results != null)
|
||||||
results.close();
|
results.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write out a log4j message
|
||||||
|
*/
|
||||||
|
private static void logInfo(BrowseInfo info)
|
||||||
|
{
|
||||||
|
if (! log.isInfoEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
log.info("Number of Results: " + info.getResultCount() +
|
||||||
|
" Overall position: " + info.getOverallPosition() +
|
||||||
|
" Total " + info.getTotal() +
|
||||||
|
" Offset " + info.getOffset());
|
||||||
|
int lastIndex = (info.getOverallPosition() + info.getResultCount());
|
||||||
|
boolean noresults = (info.getTotal() == 0) || (info.getResultCount() == 0);
|
||||||
|
|
||||||
|
if (noresults)
|
||||||
|
log.info("Got no results");
|
||||||
|
|
||||||
|
log.info("Got results: " +
|
||||||
|
info.getOverallPosition() +
|
||||||
|
" to " +
|
||||||
|
lastIndex +
|
||||||
|
" out of " + info.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the columns according to browseType.
|
||||||
|
*/
|
||||||
|
private static String getTargetColumns(int browseType)
|
||||||
|
{
|
||||||
|
return (browseType == AUTHORS_BROWSE) ? "distinct author" : "*";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a subquery clause.
|
||||||
|
* The SQL looks like this:
|
||||||
|
* or (sort_title = ? and item_id {0} 3)
|
||||||
|
*/
|
||||||
|
private static String getSubqueryClause(String column, int item_id)
|
||||||
|
{
|
||||||
|
return new StringBuffer()
|
||||||
|
.append(" or ( ")
|
||||||
|
.append(column)
|
||||||
|
// Item id must be before or after the desired item
|
||||||
|
.append(" = ? and item_id {0} ")
|
||||||
|
.append(item_id)
|
||||||
|
.append(")")
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the id from VALUE, which is either an Item or an Integer
|
||||||
|
*/
|
||||||
|
static int getItemId(Object value)
|
||||||
|
{
|
||||||
|
if (value instanceof Integer)
|
||||||
|
return ((Integer) value).intValue();
|
||||||
|
else if (value instanceof Item)
|
||||||
|
return ((Item) value).getID();
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Value must be Integer or Item");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a scoping clause to BUFFER.
|
||||||
|
*
|
||||||
|
* If scope is ALLDSPACE_SCOPE, nothing is added.
|
||||||
|
*
|
||||||
|
* Otherwise, the SQL clause which is appended looks like:
|
||||||
|
* PREFIX community_id = 7
|
||||||
|
* PREFIX collection_id = 203
|
||||||
|
*
|
||||||
|
* PREFIX may be empty, or it may be a SQL keyword like "where", "and",
|
||||||
|
* and so forth.
|
||||||
|
*/
|
||||||
|
static StringBuffer addScopeClause(StringBuffer buffer,
|
||||||
|
int scope,
|
||||||
|
Object obj,
|
||||||
|
String prefix)
|
||||||
|
{
|
||||||
|
if (scope == ALLDSPACE_SCOPE)
|
||||||
|
return buffer;
|
||||||
|
|
||||||
|
int id = (obj instanceof Community) ?
|
||||||
|
((Community) obj).getID() : ((Collection) obj).getID();
|
||||||
|
|
||||||
|
String column = (scope == COMMUNITY_SCOPE) ?
|
||||||
|
"community_id" : "collection_id";
|
||||||
|
|
||||||
|
return buffer
|
||||||
|
.append(prefix)
|
||||||
|
.append(" ")
|
||||||
|
.append(column)
|
||||||
|
.append(" = ")
|
||||||
|
.append(id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a single int value from STATEMENT.
|
* Return a single int value from STATEMENT.
|
||||||
*/
|
*/
|
||||||
@@ -1196,7 +1219,9 @@ class NormalizedTitle
|
|||||||
return title.substring(startAt);
|
return title.substring(startAt);
|
||||||
|
|
||||||
// Otherwise, return the substring with the stop word appended
|
// Otherwise, return the substring with the stop word appended
|
||||||
return new StringBuffer(title.substring(startAt)).append(", ").append(stop).toString();
|
return new StringBuffer(title.substring(startAt))
|
||||||
|
.append(", ")
|
||||||
|
.append(stop).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1246,40 +1271,6 @@ class NormalizedTitle
|
|||||||
|
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Embedded test harness
|
|
||||||
*
|
|
||||||
* @param argv - Command-line arguments
|
|
||||||
*/
|
|
||||||
public static void main(String[] argv)
|
|
||||||
{
|
|
||||||
String[] test_titles = new String[]
|
|
||||||
{
|
|
||||||
"A Test title",
|
|
||||||
"Title without stop words",
|
|
||||||
"Theater of the Absurd",
|
|
||||||
"Another Misleading Title",
|
|
||||||
"An Egg and a Bunny",
|
|
||||||
" Leading whitespace",
|
|
||||||
" An omlette",
|
|
||||||
" The Missing Link",
|
|
||||||
" Then Came You",
|
|
||||||
" Leading and trailing whitespace ",
|
|
||||||
" The An And -- Very Common Words",
|
|
||||||
"The",
|
|
||||||
" The",
|
|
||||||
"",
|
|
||||||
null
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i = 0; i < test_titles.length; i++)
|
|
||||||
{
|
|
||||||
System.out.println
|
|
||||||
("Sorting title for \"" + test_titles[i] + "\"" +
|
|
||||||
" is " + "\"" + normalizeEnglish(test_titles[i]) + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME Use BrowseScope instead?
|
// FIXME Use BrowseScope instead?
|
||||||
@@ -1433,24 +1424,35 @@ class BrowseCache
|
|||||||
public static boolean indexHasChanged(BrowseKey key)
|
public static boolean indexHasChanged(BrowseKey key)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
int tableid = BrowseTables.getTableId(key.scope, key.browseType);
|
Context context = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int tableid = BrowseTables.getTableId(key.scope, key.browseType);
|
||||||
|
|
||||||
Context context = new Context();
|
context = new Context();
|
||||||
TableRow results = countAndMax(context, key);
|
TableRow results = countAndMax(context, key);
|
||||||
long count = results != null ? results.getLongColumn("count") : -1;
|
long count = results != null ? results.getLongColumn("count") : -1;
|
||||||
int max = results != null ? results.getIntColumn("max") : -1;
|
int max = results != null ? results.getIntColumn("max") : -1;
|
||||||
context.complete();
|
context.complete();
|
||||||
|
|
||||||
// Same?
|
// Same?
|
||||||
if ((count == COUNT[tableid]) && (max == MAXIMUM[tableid]))
|
if ((count == COUNT[tableid]) && (max == MAXIMUM[tableid]))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Update the counts
|
// Update the counts
|
||||||
MAXIMUM[tableid] = max;
|
MAXIMUM[tableid] = max;
|
||||||
COUNT[tableid] = count;
|
COUNT[tableid] = count;
|
||||||
|
|
||||||
// The index has in fact changed
|
// The index has in fact changed
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
if (context != null)
|
||||||
|
context.abort();
|
||||||
|
|
||||||
|
throw sqle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1468,17 +1470,28 @@ class BrowseCache
|
|||||||
public static void updateIndexData(BrowseKey key)
|
public static void updateIndexData(BrowseKey key)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
int tableid = BrowseTables.getTableId(key.scope, key.browseType);
|
Context context = null;
|
||||||
|
|
||||||
Context context = new Context();
|
try
|
||||||
TableRow results = countAndMax(context, key);
|
{
|
||||||
long count = results != null ? results.getLongColumn("count") : -1;
|
int tableid = BrowseTables.getTableId(key.scope, key.browseType);
|
||||||
int max = results != null ? results.getIntColumn("max") : -1;
|
|
||||||
context.complete();
|
|
||||||
|
|
||||||
// Update the counts
|
context = new Context();
|
||||||
MAXIMUM[tableid] = max;
|
TableRow results = countAndMax(context, key);
|
||||||
COUNT[tableid] = count;
|
long count = results != null ? results.getLongColumn("count") : -1;
|
||||||
|
int max = results != null ? results.getIntColumn("max") : -1;
|
||||||
|
context.complete();
|
||||||
|
|
||||||
|
MAXIMUM[tableid] = max;
|
||||||
|
COUNT[tableid] = count;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (context != null)
|
||||||
|
context.abort();
|
||||||
|
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1497,18 +1510,11 @@ class BrowseCache
|
|||||||
// then some items may have been removed. We assume that
|
// then some items may have been removed. We assume that
|
||||||
// values never change.
|
// values never change.
|
||||||
|
|
||||||
int communityId = (obj instanceof Community) ?
|
StringBuffer buffer = new StringBuffer()
|
||||||
((Community) obj).getID() : -1;
|
|
||||||
int collectionId = (obj instanceof Collection) ?
|
|
||||||
((Collection) obj).getID() : -1;
|
|
||||||
|
|
||||||
String sql = new StringBuffer()
|
|
||||||
.append("select count({0}) as count, max({0}) as max from ")
|
.append("select count({0}) as count, max({0}) as max from ")
|
||||||
.append(BrowseTables.getTable(scope, browseType))
|
.append(BrowseTables.getTable(scope, browseType));
|
||||||
.append((scope == Browse.COLLECTION_SCOPE) ? " where collection_id = " : "")
|
|
||||||
.append((scope == Browse.COLLECTION_SCOPE) ? Integer.toString(collectionId) : "")
|
String sql = Browse.addScopeClause(buffer, scope, obj, "where")
|
||||||
.append((scope == Browse.COMMUNITY_SCOPE) ? " where community_id = " : "")
|
|
||||||
.append((scope == Browse.COMMUNITY_SCOPE) ? Integer.toString(communityId) : "")
|
|
||||||
.toString();
|
.toString();
|
||||||
|
|
||||||
// Format it to use the correct columns
|
// Format it to use the correct columns
|
||||||
|
Reference in New Issue
Block a user