001: /*
002: * Created on 25-Jan-2006
003: */
004: package org.apache.lucene.xmlparser.builders;
005:
006: import java.util.Map.Entry;
007:
008: import org.apache.lucene.search.CachingWrapperFilter;
009: import org.apache.lucene.search.Filter;
010: import org.apache.lucene.search.Query;
011: import org.apache.lucene.search.QueryFilter;
012: import org.apache.lucene.xmlparser.DOMUtils;
013: import org.apache.lucene.xmlparser.FilterBuilder;
014: import org.apache.lucene.xmlparser.FilterBuilderFactory;
015: import org.apache.lucene.xmlparser.ParserException;
016: import org.apache.lucene.xmlparser.QueryBuilder;
017: import org.apache.lucene.xmlparser.QueryBuilderFactory;
018: import org.w3c.dom.Element;
019:
020: /**
021: * Licensed to the Apache Software Foundation (ASF) under one or more
022: * contributor license agreements. See the NOTICE file distributed with
023: * this work for additional information regarding copyright ownership.
024: * The ASF licenses this file to You under the Apache License, Version 2.0
025: * (the "License"); you may not use this file except in compliance with
026: * the License. You may obtain a copy of the License at
027: *
028: * http://www.apache.org/licenses/LICENSE-2.0
029: *
030: * Unless required by applicable law or agreed to in writing, software
031: * distributed under the License is distributed on an "AS IS" BASIS,
032: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
033: * See the License for the specific language governing permissions and
034: * limitations under the License.
035: */
036: /**
037: * Filters are cached in an LRU Cache keyed on the contained query or filter object. Using this will
038: * speed up overall performance for repeated uses of the same expensive query/filter. The sorts of
039: * queries/filters likely to benefit from caching need not necessarily be complex - e.g. simple
040: * TermQuerys with a large DF (document frequency) can be expensive on large indexes.
041: * A good example of this might be a term query on a field with only 2 possible values -
042: * "true" or "false". In a large index, querying or filtering on this field requires reading
043: * millions of document ids from disk which can more usefully be cached as a filter bitset.
044: *
045: * For Queries/Filters to be cached and reused the object must implement hashcode and
046: * equals methods correctly so that duplicate queries/filters can be detected in the cache.
047: *
048: * The CoreParser.maxNumCachedFilters property can be used to control the size of the LRU
049: * Cache established during the construction of CoreParser instances.
050: *
051: * @author maharwood
052: */
053: public class CachedFilterBuilder implements FilterBuilder {
054:
055: private QueryBuilderFactory queryFactory;
056: private FilterBuilderFactory filterFactory;
057:
058: private LRUCache filterCache = null;
059:
060: private int cacheSize;
061:
062: public CachedFilterBuilder(QueryBuilderFactory queryFactory,
063: FilterBuilderFactory filterFactory, int cacheSize) {
064: this .queryFactory = queryFactory;
065: this .filterFactory = filterFactory;
066: this .cacheSize = cacheSize;
067: }
068:
069: public Filter getFilter(Element e) throws ParserException {
070:
071: Element childElement = DOMUtils.getFirstChildOrFail(e);
072:
073: if (filterCache == null) {
074: filterCache = new LRUCache(cacheSize);
075: }
076:
077: // Test to see if child Element is a query or filter that needs to be
078: // cached
079: QueryBuilder qb = queryFactory.getQueryBuilder(childElement
080: .getNodeName());
081: Object cacheKey = null;
082: Query q = null;
083: Filter f = null;
084: if (qb != null) {
085: q = qb.getQuery(childElement);
086: cacheKey = q;
087: } else {
088: f = filterFactory.getFilter(childElement);
089: cacheKey = f;
090: }
091: Filter cachedFilter = null;
092: synchronized (filterCache) { // check cache
093: cachedFilter = (Filter) filterCache.get(cacheKey);
094: if (cachedFilter != null) {
095: return cachedFilter; // cache hit
096: }
097: }
098:
099: //cache miss
100: if (qb != null) {
101: cachedFilter = new QueryFilter(q);
102: } else {
103: cachedFilter = new CachingWrapperFilter(f);
104: }
105:
106: synchronized (filterCache) { // update cache
107: filterCache.put(cacheKey, cachedFilter);
108: }
109: return cachedFilter;
110: }
111:
112: static class LRUCache extends java.util.LinkedHashMap {
113: public LRUCache(int maxsize) {
114: super (maxsize * 4 / 3 + 1, 0.75f, true);
115: this .maxsize = maxsize;
116: }
117:
118: protected int maxsize;
119:
120: protected boolean removeEldestEntry(Entry eldest) {
121: return size() > maxsize;
122: }
123:
124: }
125:
126: }
|