package org.apache.blur.manager;
/**
* 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.
*/
import static org.apache.blur.utils.BlurConstants.BLUR_FILTER_ALIAS;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.blur.BlurConfiguration;
import org.apache.blur.filter.FilterCache;
import org.apache.blur.log.Log;
import org.apache.blur.log.LogFactory;
import org.apache.blur.manager.writer.BlurIndex;
import org.apache.lucene.index.Term;
import org.apache.lucene.queries.BooleanFilter;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryWrapperFilter;
import org.apache.lucene.search.TermQuery;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
/**
* This implementation on {@link BlurFilterCache} does nothing and it is the
* default {@link BlurFilterCache}.
*/
public class AliasBlurFilterCache extends BlurFilterCache {
private static final Log LOG = LogFactory.getLog(AliasBlurFilterCache.class);
static class FilterKey {
final String _table;
final String _filterStr;
FilterKey(String _table, String _filterStr) {
this._table = _table;
this._filterStr = _filterStr;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((_filterStr == null) ? 0 : _filterStr.hashCode());
result = prime * result + ((_table == null) ? 0 : _table.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
FilterKey other = (FilterKey) obj;
if (_filterStr == null) {
if (other._filterStr != null)
return false;
} else if (!_filterStr.equals(other._filterStr))
return false;
if (_table == null) {
if (other._table != null)
return false;
} else if (!_table.equals(other._table))
return false;
return true;
}
}
private final Map<FilterKey, Filter> _preFilterCacheMap;
private final Map<FilterKey, Filter> _postFilterCacheMap;
private final ConcurrentMap<String, ConcurrentMap<String, String>> _tableAliasFilterMap = new ConcurrentHashMap<String, ConcurrentMap<String, String>>();
public AliasBlurFilterCache(BlurConfiguration configuration) {
super(configuration);
long _cacheEntries = 100;
_preFilterCacheMap = new ConcurrentLinkedHashMap.Builder<FilterKey, Filter>()
.maximumWeightedCapacity(_cacheEntries).build();
_postFilterCacheMap = new ConcurrentLinkedHashMap.Builder<FilterKey, Filter>().maximumWeightedCapacity(
_cacheEntries).build();
Map<String, String> properties = configuration.getProperties();
for (Entry<String, String> entry : properties.entrySet()) {
if (isFilterAlias(entry.getKey())) {
String name = getFilterAlias(entry.getKey());
int index = name.indexOf('.');
String table = name.substring(0, index);
String alias = name.substring(index + 1);
ConcurrentMap<String, String> aliasFilterMap = _tableAliasFilterMap.get(table);
if (aliasFilterMap == null) {
aliasFilterMap = new ConcurrentHashMap<String, String>();
_tableAliasFilterMap.put(table, aliasFilterMap);
}
aliasFilterMap.put(alias, entry.getValue());
}
}
}
@Override
public Filter storePreFilter(String table, String filterStr, Filter filter, FilterParser filterParser)
throws ParseException {
if (filter instanceof QueryWrapperFilter) {
QueryWrapperFilter queryWrapperFilter = (QueryWrapperFilter) filter;
Query query = queryWrapperFilter.getQuery();
Filter newFilter = buildNewFilter(query, _tableAliasFilterMap.get(table), filterParser);
FilterKey key = new FilterKey(table, filterStr);
_preFilterCacheMap.put(key, newFilter);
return newFilter;
}
return filter;
}
@Override
public Filter storePostFilter(String table, String filterStr, Filter filter, FilterParser filterParser)
throws ParseException {
return filter;
}
@Override
public Filter fetchPreFilter(String table, String filterStr) {
FilterKey filterKey = new FilterKey(table, filterStr);
return _preFilterCacheMap.get(filterKey);
}
@Override
public Filter fetchPostFilter(String table, String filterStr) {
FilterKey filterKey = new FilterKey(table, filterStr);
return _postFilterCacheMap.get(filterKey);
}
@Override
public void closing(String table, String shard, BlurIndex index) {
_tableAliasFilterMap.remove(table);
}
@Override
public void opening(String table, String shard, BlurIndex index) {
Map<String, String> properties = _configuration.getProperties();
for (Entry<String, String> entry : properties.entrySet()) {
if (isFilterAlias(entry.getKey())) {
String filterAlias = getFilterAlias(entry.getKey());
String filterQuery = entry.getValue();
Map<String, String> map = getThisTablesMap(table);
LOG.info("Loading filter alias [{0}] with query [{1}] for table [{2}]", filterAlias, filterQuery, table);
map.put(filterAlias, filterQuery);
}
}
}
private Map<String, String> getThisTablesMap(String table) {
_tableAliasFilterMap.putIfAbsent(table, new ConcurrentHashMap<String, String>());
return _tableAliasFilterMap.get(table);
}
private String getFilterAlias(String key) {
return key.substring(BLUR_FILTER_ALIAS.length());
}
private boolean isFilterAlias(String key) {
return key.startsWith(BLUR_FILTER_ALIAS);
}
private Filter buildNewFilter(Query query, ConcurrentMap<String, String> filterAlias, FilterParser filterParser)
throws ParseException {
if (query instanceof BooleanQuery) {
BooleanQuery booleanQuery = (BooleanQuery) query;
BooleanFilter booleanFilter = new BooleanFilter();
for (BooleanClause clause : booleanQuery.clauses()) {
booleanFilter.add(buildNewFilter(clause.getQuery(), filterAlias, filterParser), clause.getOccur());
}
return booleanFilter;
} else if (query instanceof TermQuery) {
TermQuery termQuery = (TermQuery) query;
Term term = termQuery.getTerm();
String key = term.toString();
String queryStr = filterAlias.get(key);
if (queryStr == null) {
return new QueryWrapperFilter(termQuery);
}
String id = getId(key);
return new FilterCache(id, new QueryWrapperFilter(filterParser.parse(queryStr)));
} else {
return new QueryWrapperFilter(query);
}
}
private String getId(String key) {
return key.replace(':', '-');
}
}