| /* |
| * 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. |
| */ |
| package org.apache.usergrid.persistence.index.impl; |
| |
| |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.usergrid.persistence.core.scope.ApplicationScope; |
| import org.apache.usergrid.persistence.index.IndexEdge; |
| import org.apache.usergrid.persistence.model.entity.Entity; |
| import org.apache.usergrid.persistence.model.entity.EntityMap; |
| import org.apache.usergrid.persistence.model.entity.Id; |
| |
| import com.google.common.base.Optional; |
| |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.APPLICATION_ID_FIELDNAME; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.EDGE_NAME_FIELDNAME; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.EDGE_NODE_ID_FIELDNAME; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.EDGE_NODE_TYPE_FIELDNAME; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.EDGE_SEARCH_FIELDNAME; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.EDGE_TIMESTAMP_FIELDNAME; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.ENTITY_FIELDS; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.ENTITY_ID_FIELDNAME; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.ENTITY_SIZE_FIELDNAME; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.ENTITY_TYPE_FIELDNAME; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.ENTITY_VERSION_FIELDNAME; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.applicationId; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.entityId; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.getType; |
| import static org.apache.usergrid.persistence.index.impl.IndexingUtils.nodeId; |
| |
| |
| /** |
| * Convert a CP entity to an elasticsearch document |
| */ |
| public class EntityToMapConverter { |
| |
| |
| public static Map<String, Object> convert(ApplicationScope applicationScope, final IndexEdge indexEdge, |
| final Entity entity) { |
| |
| return convert( applicationScope, indexEdge, entity, Optional.absent() ); |
| } |
| |
| /** |
| * Set the entity as a map with the context |
| * |
| * @param applicationScope |
| * @param entity The entity |
| * @param indexEdge The edge this entity is indexed on |
| * @param fieldsToIndex A set of fields that will be indexed should they exist on the entity. Other fields will be filtered out. |
| */ |
| public static Map<String, Object> convert(ApplicationScope applicationScope, final IndexEdge indexEdge, |
| final Entity entity, Optional<Set<String>> fieldsToIndex) { |
| |
| |
| |
| final Map<String, Object> outputEntity = new HashMap<>(); |
| |
| |
| final Id entityId = entity.getId(); |
| |
| /*** |
| * Add our static fields for easier admin/debugging/reporting |
| ****/ |
| |
| outputEntity.put( ENTITY_ID_FIELDNAME, entityId( entityId ) ); |
| |
| outputEntity.put( ENTITY_VERSION_FIELDNAME, entity.getVersion() ); |
| |
| outputEntity.put( ENTITY_TYPE_FIELDNAME, getType( applicationScope, entityId)); |
| |
| outputEntity.put( APPLICATION_ID_FIELDNAME, applicationId( applicationScope.getApplication() ) ); |
| |
| outputEntity.put( EDGE_NODE_ID_FIELDNAME, nodeId( indexEdge.getNodeId() ) ); |
| |
| outputEntity.put( EDGE_NODE_TYPE_FIELDNAME, indexEdge.getNodeType() ); |
| |
| outputEntity.put( EDGE_NAME_FIELDNAME, indexEdge.getEdgeName() ); |
| |
| outputEntity.put( EDGE_TIMESTAMP_FIELDNAME, indexEdge.getTimestamp() ); |
| |
| outputEntity.put( ENTITY_SIZE_FIELDNAME, entity.getSize() ); |
| |
| //add the context for filtering later |
| outputEntity.put( EDGE_SEARCH_FIELDNAME, IndexingUtils.createContextName( applicationScope, indexEdge ) ); |
| |
| //migrate the entity to map since we're ultimately going to use maps once we get rid of the Field objects |
| final EntityMap entityMap = EntityMap.fromEntity( entity ); |
| |
| //now visit our entity |
| final FieldParser parser = new EntityMappingParser(); |
| |
| final Set<EntityField> fieldsToBeFiltered = parser.parse( entityMap ); |
| |
| //add our fields to output entity |
| outputEntity.put( ENTITY_FIELDS, fieldsToBeFiltered ); |
| |
| if(fieldsToIndex.isPresent()){ |
| Set<String> defaultProperties = fieldsToIndex.get(); |
| HashSet mapFields = ( HashSet ) outputEntity.get( "fields" ); |
| Iterator collectionIterator = mapFields.iterator(); |
| |
| //Loop through all of the fields of the flatted entity and check to see if they should be filtered out. |
| collectionIterator.forEachRemaining(outputEntityField -> { |
| EntityField testedField = ( EntityField ) outputEntityField; |
| String fieldName = ( String ) ( testedField ).get( "name" ); |
| |
| //could move this down into the method below |
| if ( !defaultProperties.contains( fieldName ) ) { |
| iterateThroughMapForFieldsToBeIndexed( defaultProperties, collectionIterator, fieldName ); |
| } |
| }); |
| |
| } |
| |
| |
| |
| return outputEntity; |
| } |
| |
| /** |
| * Handles checking to see if a field is a top level exclusion or just a field that shouldn't be indexed. |
| * This is handled by looping through all the fields we want to be able to query on, and checking to see if a |
| * specific field name is included. If the field name is included then do nothing. If the field name is not included |
| * then we do not want to be able to query on it. Instead we remove it from the collectionIterator which |
| * removes it from the outputEntity above, thus filtering it out. |
| * |
| * @param fieldsToKeep - contains a list of fields that the user defined in their schema. |
| * @param collectionIterator - contains the iterator with the reference to the map where we want to remove the field. Once removed here it is removed from the entity so it won't be indexed. |
| * @param fieldName - contains the name of the field that we want to keep. |
| */ |
| private static void iterateThroughMapForFieldsToBeIndexed( final Set<String> fieldsToKeep, |
| final Iterator collectionIterator, |
| final String fieldName ) { |
| boolean toRemoveFlag = true; |
| Iterator fieldIterator = fieldsToKeep.iterator(); |
| |
| |
| |
| //goes through a loop of all the fields that we want to keep. |
| //if the toRemoveFlag is set to false then we want to keep the property and do nothing to it, otherwise we set it to true and remove |
| //the property. |
| while ( fieldIterator.hasNext() ) { |
| //this is the field that we're |
| String fieldToKeep = ( String ) fieldIterator.next(); |
| |
| |
| //Since we know that the fieldName cannot be equal to the requiredInclusion criteria due to the if condition before we enter this method |
| //and we are certain that the indexing criteria is shorter we want to be sure that the inclusion criteria |
| //is contained within the field we're evaluating. i.e that one.two.three contains one.two |
| |
| //The second part of the if loop also requires that the fieldName is followed by a period after we check to ensure that the |
| //indexing criteria is included in the string. This is done to weed out values such as one.twoexample.three |
| // when we should only keep one.two.three when comparing the indexing criteria of one.two. |
| if(fieldName.length() > fieldToKeep.length() |
| && fieldName.contains( fieldToKeep ) |
| && fieldName.charAt( fieldToKeep.length() )=='.' ) { |
| toRemoveFlag = false; |
| break; |
| } |
| else { |
| //the of the field we're evaluating is shorter than the indexing criteria so it can't match. |
| //Move onto the next field and see if they match. |
| toRemoveFlag = true; |
| } |
| } |
| |
| if ( toRemoveFlag ) { |
| collectionIterator.remove(); |
| } |
| } |
| } |
| |