com.impetus.client.cassandra.index.InvertedIndexHandlerBase Maven / Gradle / Ivy
/**
* Copyright 2012 Impetus Infotech.
*
* Licensed 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 com.impetus.client.cassandra.index;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.persistence.PersistenceException;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.thrift.Column;
import org.apache.cassandra.thrift.ConsistencyLevel;
import org.apache.cassandra.thrift.IndexClause;
import org.apache.cassandra.thrift.IndexExpression;
import org.apache.cassandra.thrift.IndexOperator;
import org.apache.cassandra.thrift.SuperColumn;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.impetus.kundera.Constants;
import com.impetus.kundera.db.SearchResult;
import com.impetus.kundera.metadata.model.EntityMetadata;
import com.impetus.kundera.metadata.model.MetamodelImpl;
import com.impetus.kundera.metadata.model.attributes.DefaultSingularAttribute;
import com.impetus.kundera.persistence.EntityManagerFactoryImpl.KunderaMetadata;
import com.impetus.kundera.property.PropertyAccessorHelper;
import com.impetus.kundera.query.QueryHandlerException;
import com.impetus.kundera.utils.TimestampGenerator;
/**
* Base class for
*
* @author amresh.singh
*/
public abstract class InvertedIndexHandlerBase
{
/** log for this class. */
private static Logger log = LoggerFactory.getLogger(InvertedIndexHandlerBase.class);
protected boolean useSecondryIndex;
/** For time stamp generation. */
protected final TimestampGenerator generator;
public InvertedIndexHandlerBase(final TimestampGenerator generator)
{
this.generator = generator;
}
public List search(EntityMetadata m, String persistenceUnit, ConsistencyLevel consistencyLevel,
Map> indexClauseMap)
{
String columnFamilyName = m.getTableName() + Constants.INDEX_TABLE_SUFFIX;
List searchResults = new ArrayList();
boolean isRowKeyQuery = indexClauseMap.keySet().iterator().next();
for (IndexClause o : indexClauseMap.get(isRowKeyQuery))
{
for (IndexExpression expression : o.getExpressions())
{
searchAndAddToResults(m, persistenceUnit, consistencyLevel, columnFamilyName, searchResults,
expression, isRowKeyQuery);
}
}
return searchResults;
}
/**
* Searches into inverted index based on expression
and adds
* search result to searchResults
*/
private void searchAndAddToResults(EntityMetadata m, String persistenceUnit, ConsistencyLevel consistencyLevel,
String columnFamilyName, List searchResults, IndexExpression expression, boolean isRowKeyQuery)
{
SearchResult searchResult = new SearchResult();
byte[] superColumnName = expression.getValue();
String superColumnNameStr = null;
String rowKey = null;
try
{
rowKey = ByteBufferUtil.string(ByteBuffer.wrap(expression.getColumn_name()),
Charset.forName(Constants.CHARSET_UTF8));
superColumnNameStr = new String(expression.getValue(), Charset.forName(Constants.CHARSET_UTF8));
}
catch (CharacterCodingException e)
{
log.error("Error while retrieving records {}, Caused by:", e);
throw new PersistenceException(e);
}
Object pk = PropertyAccessorHelper.getObject(m.getIdAttribute().getJavaType(), superColumnName);
IndexOperator condition = expression.getOp();
if (log.isInfoEnabled())
{
log.info("RowKey: {} ; Super column Name: {} on condition.", rowKey, superColumnNameStr, condition);
}
// TODO: Second check unnecessary but unavoidable as filter clause
// property is incorrectly passed as column name
// Search based on Primary key
if (isRowKeyQuery
&& (rowKey.equals(m.getIdAttribute().getName()) || rowKey.equals(((DefaultSingularAttribute) m
.getIdAttribute()).getJPAColumnName())))
{
if (searchResults.isEmpty())
{
searchResult.setPrimaryKey(pk);
searchResults.add(searchResult);
}
else
{
SearchResult existing = searchResults.get(0);
if (existing.getPrimaryKey() != null && existing.getPrimaryKey().equals(superColumnNameStr))
{
searchResults.add(searchResult);
}
else
{
searchResults.remove(0);
}
}
}
else
{
// Search results in the form of thrift super columns
List thriftSuperColumns = new ArrayList();
switch (condition)
{
// EQUAL Operator
case EQ:
SuperColumn thriftSuperColumn = getSuperColumnForRow(consistencyLevel, columnFamilyName, rowKey,
superColumnName, persistenceUnit);
if (thriftSuperColumn != null)
thriftSuperColumns.add(thriftSuperColumn);
break;
// LIKE operation not available
// Greater than operator
case GT:
searchSuperColumnsInRange(columnFamilyName, consistencyLevel, persistenceUnit, rowKey, superColumnName,
thriftSuperColumns, superColumnName, new byte[0]);
break;
// Less than Operator
case LT:
searchSuperColumnsInRange(columnFamilyName, consistencyLevel, persistenceUnit, rowKey, superColumnName,
thriftSuperColumns, new byte[0], superColumnName);
break;
// Greater than-equals to operator
case GTE:
searchSuperColumnsInRange(columnFamilyName, consistencyLevel, persistenceUnit, rowKey, superColumnName,
thriftSuperColumns, superColumnName, new byte[0]);
break;
// Less than equal to operator
case LTE:
searchSuperColumnsInRange(columnFamilyName, consistencyLevel, persistenceUnit, rowKey, superColumnName,
thriftSuperColumns, new byte[0], superColumnName);
break;
default:
throw new QueryHandlerException(condition
+ " comparison operator not supported currently for Cassandra Inverted Index.");
}
// Construct search results out of these thrift columns
for (SuperColumn thriftSuperColumn : thriftSuperColumns)
{
for (Column column : thriftSuperColumn.getColumns())
{
byte[] columnName = column.getName();
searchResult.setPrimaryKey(PropertyAccessorHelper.getObject(m.getIdAttribute().getJavaType(),
columnName));
byte[] columnValue = column.getValue();
String ecValue = UTF8Type.instance.compose(ByteBuffer.wrap(columnValue));
if (ecValue != null && !"".equals(ecValue.trim()))
{
searchResult.setEmbeddedColumnName(rowKey.substring(0,
rowKey.indexOf(Constants.INDEX_TABLE_ROW_KEY_DELIMITER)));
searchResult.addEmbeddedColumnValue(ecValue);
}
}
if (searchResults.isEmpty())
{
searchResults.add(searchResult);
}
else
{
SearchResult existing = searchResults.get(0);
if (existing.getPrimaryKey() != null
&& existing.getPrimaryKey().equals(searchResult.getPrimaryKey()))
{
searchResults.add(searchResult);
}
else
{
searchResults.remove(0);
}
}
}
}
}
public void delete(Object entity, EntityMetadata metadata, ConsistencyLevel consistencyLevel,
final KunderaMetadata kunderaMetadata)
{
MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
metadata.getPersistenceUnit());
if (CassandraIndexHelper.isInvertedIndexingApplicable(metadata, useSecondryIndex))
{
String indexColumnFamily = CassandraIndexHelper.getInvertedIndexTableName(metadata.getTableName());
Map embeddables = metaModel.getEmbeddables(metadata.getEntityClazz());
EntityType entityType = metaModel.entity(metadata.getEntityClazz());
byte[] columnName = PropertyAccessorHelper.get(entity, (Field) metadata.getIdAttribute().getJavaMember());
for (String fieldName : embeddables.keySet())
{
EmbeddableType embeddedColumn = embeddables.get(fieldName);
Attribute embeddedAttribute = entityType.getAttribute(fieldName);
Object embeddedObject = PropertyAccessorHelper.getObject(entity,
(Field) embeddedAttribute.getJavaMember());
if (embeddedObject != null)
{
if (embeddedObject instanceof Collection)
{
for (Object obj : (Collection) embeddedObject)
{
Iterator iter = embeddedColumn.getAttributes().iterator();
while (iter.hasNext())
{
Attribute attrib = iter.next();
String rowKey = embeddedAttribute.getName() + Constants.INDEX_TABLE_ROW_KEY_DELIMITER
+ attrib.getName();
byte[] superColumnName = PropertyAccessorHelper
.get(obj, (Field) attrib.getJavaMember());
if (superColumnName != null)
{
deleteColumn(indexColumnFamily, rowKey, superColumnName,
metadata.getPersistenceUnit(), consistencyLevel, columnName);
}
}
}
}
else
{
Iterator iter = embeddedColumn.getAttributes().iterator();
while (iter.hasNext())
{
Attribute attrib = iter.next();
String rowKey = embeddedAttribute.getName() + Constants.INDEX_TABLE_ROW_KEY_DELIMITER
+ attrib.getName();
byte[] superColumnName = PropertyAccessorHelper.get(embeddedObject,
(Field) attrib.getJavaMember());
if (superColumnName != null)
{
deleteColumn(indexColumnFamily, rowKey, superColumnName, metadata.getPersistenceUnit(),
consistencyLevel, columnName);
}
}
}
}
}
}
}
/**
* @param indexColumnFamily
* @param rowKey
* @param superColumnName
* @param columnName
* TODO
*/
protected abstract void deleteColumn(String indexColumnFamily, String rowKey, byte[] superColumnName,
String persistenceUnit, ConsistencyLevel consistencyLevel, byte[] columnName);
/**
* @param consistencyLevel
* @param columnFamilyName
* @param rowKey
* @param superColumnName
* @return
*/
protected abstract SuperColumn getSuperColumnForRow(ConsistencyLevel consistencyLevel, String columnFamilyName,
String rowKey, byte[] superColumnName, String persistenceUnit);
protected abstract void searchSuperColumnsInRange(String columnFamilyName, ConsistencyLevel consistencyLevel,
String persistenceUnit, String rowKey, byte[] searchSuperColumnName, List thriftSuperColumns,
byte[] start, byte[] finish);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy