diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityPropertyTypeDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityPropertyTypeDAO.java
index afaf16b741608a2446b6be8ae505fa23e2bda137..ec60ba102b137e5fe587ff9a0bddf0f103eb98c0 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityPropertyTypeDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityPropertyTypeDAO.java
@@ -36,8 +36,8 @@ import org.springframework.orm.hibernate3.HibernateTemplate;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IEntityPropertyTypeDAO;
-import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.EntitiesToUpdate;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IFullTextIndexUpdateScheduler;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexUpdateOperation;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ColumnNames;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE;
@@ -445,7 +445,7 @@ final class EntityPropertyTypeDAO extends AbstractDAO implements IEntityProperty
 
     private void scheduleFullTextIndexUpdate(List<Long> entityIds)
     {
-        fullTextIndexUpdateScheduler.scheduleUpdate(new EntitiesToUpdate(
+        fullTextIndexUpdateScheduler.scheduleUpdate(IndexUpdateOperation.reindex(
                 getIndexedEntityClass(entityKind), entityIds));
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/IndexCreationUtil.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/IndexCreationUtil.java
index 380a6e84c299ad2d4be1ec5055490ecfc2a63a65..e8b0b782bf046a1d608d95064c5dbb615a752a6a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/IndexCreationUtil.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/IndexCreationUtil.java
@@ -35,11 +35,11 @@ import ch.systemsx.cisd.common.logging.LogInitializer;
 import ch.systemsx.cisd.common.process.ProcessExecutionHelper;
 import ch.systemsx.cisd.common.utilities.Template;
 import ch.systemsx.cisd.dbmigration.postgresql.DumpPreparator;
-import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.EntitiesToUpdate;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.FullTextIndexerRunnable;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.HibernateSearchContext;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IFullTextIndexUpdater;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexMode;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexUpdateOperation;
 
 /**
  * Utility methods around database indexing with <i>Hibernate</i>.
@@ -110,7 +110,7 @@ public final class IndexCreationUtil
                 {
                 }
 
-                public void scheduleUpdate(EntitiesToUpdate entities)
+                public void scheduleUpdate(IndexUpdateOperation entities)
                 {
                 }
             };
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexer.java
index 7364db575789c7c2ab2e0fbbbb6c219b4841d56f..ab0b9ed4389f1b0385f187a27379b9e0214bc697 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexer.java
@@ -95,7 +95,10 @@ final class DefaultFullTextIndexer implements IFullTextIndexer
             final long maxId = ids.get(nextIndex);
             final List<T> results =
                     listEntitiesWithRestrictedId(fullTextSession, clazz, minId, maxId);
-            index = indexEntities(fullTextSession, results, clazz, index);
+            indexEntities(fullTextSession, results, clazz);
+            index = nextIndex;
+            operationLog.info(String.format("%d %ss have been indexed...", index, clazz
+                    .getSimpleName()));
         }
         fullTextSession.getSearchFactory().optimize(clazz);
         operationLog.info(String.format("'%s' index complete. %d entities have been indexed.",
@@ -119,7 +122,10 @@ final class DefaultFullTextIndexer implements IFullTextIndexer
             final int nextIndex = getNextIndex(index, maxIndex);
             List<Long> subList = ids.subList(index, nextIndex);
             final List<T> results = listEntitiesWithRestrictedId(fullTextSession, clazz, subList);
-            index = indexEntities(fullTextSession, results, clazz, index);
+            indexEntities(fullTextSession, results, clazz);
+            index = nextIndex;
+            operationLog.info(String.format("%d %ss have been reindexed...", index, clazz
+                    .getSimpleName()));
         }
         fullTextSession.getSearchFactory().optimize(clazz);
         transaction.commit();
@@ -127,6 +133,24 @@ final class DefaultFullTextIndexer implements IFullTextIndexer
                 clazz.getSimpleName(), index));
     }
 
+    public <T> void removeFromIndex(final Session hibernateSession, final Class<T> clazz,
+            final List<Long> ids) throws DataAccessException
+    {
+        operationLog.info(String.format("Removing %s %ss...", ids.size(), clazz.getSimpleName()));
+        final FullTextSession fullTextSession = getFullTextSession(hibernateSession);
+
+        // removing from index doesn't require a lot of resources - don't need to use batches
+        final Transaction transaction = fullTextSession.beginTransaction();
+        for (Long id : ids)
+        {
+            fullTextSession.purge(clazz, id);
+        }
+        fullTextSession.getSearchFactory().optimize(clazz);
+        transaction.commit();
+        operationLog.info(String.format("'%s' index is updated. %d entities have been removed.",
+                clazz.getSimpleName(), ids.size()));
+    }
+
     private int getNextIndex(int index, int maxIndex)
     {
         return Math.min(index + batchSize, maxIndex);
@@ -140,20 +164,15 @@ final class DefaultFullTextIndexer implements IFullTextIndexer
         return fullTextSession;
     }
 
-    private static final <T> int indexEntities(final FullTextSession fullTextSession,
-            final List<T> entities, final Class<T> clazz, final int oldCounter)
+    private static final <T> void indexEntities(final FullTextSession fullTextSession,
+            final List<T> entities, final Class<T> clazz)
     {
-        int counter = oldCounter;
         for (T entity : entities)
         {
             indexEntity(fullTextSession, entity);
-            counter++;
         }
-        operationLog.info(String.format("%d %ss have been indexed...", counter, clazz
-                .getSimpleName()));
         fullTextSession.flushToIndexes();
         fullTextSession.clear();
-        return counter;
     }
 
     private static final <T> List<Long> getAllIds(final FullTextSession fullTextSession,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexUpdater.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexUpdater.java
index 942088118d04b22b412821c09354833d0091696f..0459642e7ec882009e0e9e696156d602b9a2a860 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexUpdater.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexUpdater.java
@@ -49,7 +49,7 @@ public final class FullTextIndexUpdater extends HibernateDaoSupport implements
 
     private final IFullTextIndexer fullTextIndexer;
 
-    private final IExtendedBlockingQueue<EntitiesToUpdate> updaterQueue;
+    private final IExtendedBlockingQueue<IndexUpdateOperation> updaterQueue;
 
     public FullTextIndexUpdater(final SessionFactory sessionFactory,
             final HibernateSearchContext context)
@@ -62,7 +62,8 @@ public final class FullTextIndexUpdater extends HibernateDaoSupport implements
         File queueFile = getUpdaterQueueFile(context);
         operationLog.debug(String.format("Updater queue file: %s.", queueFile));
         updaterQueue =
-                ExtendedBlockingQueueFactory.<EntitiesToUpdate> createPersistRecordBased(queueFile);
+                ExtendedBlockingQueueFactory
+                        .<IndexUpdateOperation> createPersistRecordBased(queueFile);
     }
 
     private static File getUpdaterQueueFile(HibernateSearchContext context)
@@ -89,13 +90,13 @@ public final class FullTextIndexUpdater extends HibernateDaoSupport implements
         }
     }
 
-    public void scheduleUpdate(EntitiesToUpdate entities)
+    public void scheduleUpdate(IndexUpdateOperation operation)
     {
         if (operationLog.isDebugEnabled())
         {
-            operationLog.debug("Scheduling update: " + entities);
+            operationLog.debug("Scheduling update: " + operation);
         }
-        updaterQueue.add(entities);
+        updaterQueue.add(operation);
     }
 
     /**
@@ -118,10 +119,10 @@ public final class FullTextIndexUpdater extends HibernateDaoSupport implements
             {
                 while (true)
                 {
-                    final EntitiesToUpdate entities = updaterQueue.peekWait();
+                    final IndexUpdateOperation operation = updaterQueue.peekWait();
                     if (operationLog.isInfoEnabled())
                     {
-                        operationLog.info("Updating " + entities);
+                        operationLog.info("Update: " + operation);
                     }
                     final StopWatch stopWatch = new StopWatch();
                     stopWatch.start();
@@ -129,12 +130,20 @@ public final class FullTextIndexUpdater extends HibernateDaoSupport implements
                     try
                     {
                         session = getSession();
-                        fullTextIndexer.doFullTextIndexUpdate(getSession(), entities.getClazz(),
-                                entities.getIds());
+                        switch (operation.getOperationKind())
+                        {
+                            case REINDEX:
+                                fullTextIndexer.doFullTextIndexUpdate(getSession(), operation
+                                        .getClazz(), operation.getIds());
+                                break;
+                            case REMOVE:
+                                fullTextIndexer.removeFromIndex(getSession(), operation.getClazz(),
+                                        operation.getIds());
+                        }
                         stopWatch.stop();
                     } catch (RuntimeException e)
                     {
-                        notificationLog.error("Error updating " + entities + ".", e);
+                        notificationLog.error("Error: " + operation + ".", e);
                     } finally
                     {
                         if (session != null)
@@ -144,8 +153,9 @@ public final class FullTextIndexUpdater extends HibernateDaoSupport implements
                     }
                     if (operationLog.isInfoEnabled())
                     {
-                        operationLog.info("Updating " + entities.getIds().size() + " "
-                                + entities.getClazz().getSimpleName() + "s took " + stopWatch);
+                        operationLog.info(operation.getOperationKind() + " of "
+                                + operation.getIds().size() + " "
+                                + operation.getClazz().getSimpleName() + "s took " + stopWatch);
                     }
                     updaterQueue.take();
                 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexerRunnable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexerRunnable.java
index fde10920c49f6b460f12f43a3069c90a569d4584..ccbe01e8b208771dc11e6662af4a8934a654213b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexerRunnable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexerRunnable.java
@@ -86,6 +86,12 @@ public final class FullTextIndexerRunnable extends HibernateDaoSupport implement
         }
         final Set<Class<?>> indexedEntities = indexedEntityFinder.getIndexedEntities();
 
+        // Use code below for debugging if not all entities need to be indexed.
+        //
+        // final Set<Class<?>> indexedEntities = new HashSet<Class<?>>();
+        // indexedEntities.add(ExternalDataPE.class);
+        // indexedEntities.add(ExperimentPE.class);
+
         if (indexedEntities.size() == 0)
         {
             operationLog.info(String.format("No entity annotated with '%s' has been found.",
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexUpdateScheduler.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexUpdateScheduler.java
index 6bdb6b2583e180458ab0136036f0f6db570f6113..81ca1bb53ae82b89d2740b0979acb58785e3e1d4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexUpdateScheduler.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexUpdateScheduler.java
@@ -26,7 +26,7 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search;
 public interface IFullTextIndexUpdateScheduler
 {
     /**
-     * Schedules update of index for specified entities.
+     * Schedules specified operation.
      */
-    void scheduleUpdate(EntitiesToUpdate entities);
+    void scheduleUpdate(IndexUpdateOperation operation);
 }
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexer.java
index 6758664ce985bdecafd270f886f243fec957ce94..a0e484f72aac02e60387b8d61c87f3f3bbc6fd92 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexer.java
@@ -43,4 +43,11 @@ public interface IFullTextIndexer
      */
     public <T> void doFullTextIndexUpdate(final Session hibernateSession, final Class<T> clazz,
             final List<Long> ids) throws DataAccessException;
+
+    /**
+     * Removes entities of given <var>clazz</var> with given <var>ids</var> from the
+     * <i>full-text</i> index using given <i>Hibernate</i> session.
+     */
+    public <T> void removeFromIndex(final Session hibernateSession, final Class<T> clazz,
+            final List<Long> ids) throws DataAccessException;
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/EntitiesToUpdate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IndexUpdateOperation.java
similarity index 52%
rename from openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/EntitiesToUpdate.java
rename to openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IndexUpdateOperation.java
index dffb3451fe12190c17f1135ab24743b6c819baa5..d2f52663004b001aa19bf15ac0bc9bc868bd2324 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/EntitiesToUpdate.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IndexUpdateOperation.java
@@ -22,20 +22,45 @@ import java.util.List;
 import ch.systemsx.cisd.common.collections.CollectionUtils;
 
 /**
+ * Encapsulates operation kind and data for an update operation to be performed on an index.
+ * 
  * @author Piotr Buczek
  */
-public class EntitiesToUpdate implements Serializable
+public class IndexUpdateOperation implements Serializable
 {
+    public enum IndexUpdateOperationKind
+    {
+        /** update indexed entity */
+        REINDEX,
+
+        /** remove from index */
+        REMOVE
+    }
+
     private static final long serialVersionUID = 1L;
 
     private final Class<?> clazz;
 
     private final List<Long> ids;
 
-    public EntitiesToUpdate(Class<?> clazz, List<Long> ids)
+    private final IndexUpdateOperationKind operationKind;
+
+    public static IndexUpdateOperation remove(Class<?> clazz, List<Long> ids)
+    {
+        return new IndexUpdateOperation(IndexUpdateOperationKind.REMOVE, clazz, ids);
+    }
+
+    public static IndexUpdateOperation reindex(Class<?> clazz, List<Long> ids)
+    {
+        return new IndexUpdateOperation(IndexUpdateOperationKind.REINDEX, clazz, ids);
+    }
+
+    private IndexUpdateOperation(IndexUpdateOperationKind operationKind, Class<?> clazz,
+            List<Long> ids)
     {
         this.clazz = clazz;
         this.ids = ids;
+        this.operationKind = operationKind;
     }
 
     public Class<?> getClazz()
@@ -48,10 +73,15 @@ public class EntitiesToUpdate implements Serializable
         return ids;
     }
 
+    public IndexUpdateOperationKind getOperationKind()
+    {
+        return operationKind;
+    }
+
     @Override
     public String toString()
     {
-        return clazz.getName() + ": " + CollectionUtils.abbreviate(ids, 10);
+        return operationKind + " " + clazz.getName() + ": " + CollectionUtils.abbreviate(ids, 10);
     }
 
 }