/** * Copyright (c) 2002-2011 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.neo4j.index.impl.lucene; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.lucene.search.Query; import org.apache.lucene.search.Searcher; import org.neo4j.helpers.Pair; public class ExactTxData extends TxData { private Map<String, Map<Object, Set<Object>>> data; ExactTxData( LuceneIndex index ) { super( index ); } @Override TxData add( Object entityId, String key, Object value ) { idCollection( key, value, true ).add( entityId ); return this; } private Set<Object> idCollection( String key, Object value, boolean create ) { Map<Object, Set<Object>> keyMap = keyMap( key, create ); if ( keyMap == null ) { return null; } Set<Object> ids = keyMap.get( value ); if ( ids == null && create ) { ids = new HashSet<Object>(); keyMap.put( value, ids ); } return ids; } private Map<Object, Set<Object>> keyMap( String key, boolean create ) { if ( data == null ) { if ( create ) { data = new HashMap<String, Map<Object,Set<Object>>>(); } else { return null; } } Map<Object, Set<Object>> inner = data.get( key ); if ( inner == null && create ) { inner = new HashMap<Object, Set<Object>>(); data.put( key, inner ); } return inner; } private TxData toFullTxData() { FullTxData data = new FullTxData( index ); if ( this.data != null ) { for ( Map.Entry<String, Map<Object, Set<Object>>> entry : this.data.entrySet() ) { String key = entry.getKey(); for ( Map.Entry<Object, Set<Object>> valueEntry : entry.getValue().entrySet() ) { Object value = valueEntry.getKey(); for ( Object id : valueEntry.getValue() ) { data.add( id, key, value ); } } } } return data; } @Override void close() { } @Override Pair<Collection<Long>, TxData> query( Query query, QueryContext contextOrNull ) { if ( contextOrNull != null && contextOrNull.tradeCorrectnessForSpeed ) { return Pair.<Collection<Long>, TxData>of( Collections.<Long>emptyList(), this ); } return toFullTxData().query( query, contextOrNull ); } @Override TxData remove( Object entityId, String key, Object value ) { if ( data == null ) { return this; } Collection<Object> ids = idCollection( key, value, false ); if ( ids != null ) { ids.remove( entityId ); } return this; } @Override Pair<Collection<Long>, TxData> get( String key, Object value ) { value = value instanceof ValueContext ? ((ValueContext) value).getCorrectValue() : value.toString(); Set<Object> ids = idCollection( key, value, false ); if ( ids == null || ids.isEmpty() ) { return Pair.<Collection<Long>, TxData>of( Collections.<Long>emptySet(), this ); } return Pair.<Collection<Long>, TxData>of( toLongs( ids ), this ); } private Collection<Long> toLongs( Set<Object> ids ) { if ( ids.iterator().next() instanceof Long ) { return (Collection) ids; } else { Collection<Long> longs = new ArrayList<Long>(); for ( Object id : ids ) { longs.add( ((RelationshipId) id).id ); } return longs; } } @Override Pair<Searcher, TxData> asSearcher( QueryContext context ) { if ( context != null && context.tradeCorrectnessForSpeed ) { return Pair.<Searcher, TxData>of( null, this ); } return toFullTxData().asSearcher( context ); } }