diff --git a/common/source/java/ch/systemsx/cisd/common/shared/basic/AlternativesStringFilter.java b/common/source/java/ch/systemsx/cisd/common/shared/basic/AlternativesStringFilter.java
index 458c21c941157840dc996661f1c34956db780c6b..e36dd81a1b328bc309242e4a1beec317c060f9ba 100644
--- a/common/source/java/ch/systemsx/cisd/common/shared/basic/AlternativesStringFilter.java
+++ b/common/source/java/ch/systemsx/cisd/common/shared/basic/AlternativesStringFilter.java
@@ -17,7 +17,9 @@
 package ch.systemsx.cisd.common.shared.basic;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import ch.systemsx.cisd.common.shared.basic.utils.StringUtils;
 
@@ -56,31 +58,28 @@ public class AlternativesStringFilter
         boolean matches(String value);
     }
 
-    static abstract class AbstractMatcher implements Matcher
+    static abstract class AbstractTextMatcher implements Matcher
     {
         protected final String filterText;
 
-        protected final boolean comparisonValue;
-
-        AbstractMatcher(String filterText, boolean comparisonValue)
+        AbstractTextMatcher(String filterText)
         {
             this.filterText = filterText.toLowerCase().replace(ESCAPE, StringUtils.EMPTY_STRING);
-            this.comparisonValue = comparisonValue;
         }
 
         abstract boolean doMatch(String value);
 
         public boolean matches(String value)
         {
-            return doMatch(value) == comparisonValue;
+            return doMatch(value);
         }
     }
 
-    static class ContainsMatcher extends AbstractMatcher
+    static class ContainsMatcher extends AbstractTextMatcher
     {
-        ContainsMatcher(String filterText, boolean comparisonValue)
+        ContainsMatcher(String filterText)
         {
-            super(filterText, comparisonValue);
+            super(filterText);
         }
 
         @Override
@@ -91,11 +90,11 @@ public class AlternativesStringFilter
 
     }
 
-    static class StartAnchorMatcher extends AbstractMatcher
+    static class StartAnchorMatcher extends AbstractTextMatcher
     {
-        StartAnchorMatcher(String filterText, boolean comparisonValue)
+        StartAnchorMatcher(String filterText)
         {
-            super(filterText, comparisonValue);
+            super(filterText);
         }
 
         @Override
@@ -106,11 +105,11 @@ public class AlternativesStringFilter
 
     }
 
-    static class EndAnchorMatcher extends AbstractMatcher
+    static class EndAnchorMatcher extends AbstractTextMatcher
     {
-        EndAnchorMatcher(String filterText, boolean comparisonValue)
+        EndAnchorMatcher(String filterText)
         {
-            super(filterText, comparisonValue);
+            super(filterText);
         }
 
         @Override
@@ -121,11 +120,11 @@ public class AlternativesStringFilter
 
     }
 
-    static class EqualsMatcher extends AbstractMatcher
+    static class EqualsMatcher extends AbstractTextMatcher
     {
-        EqualsMatcher(String filterText, boolean comparisonValue)
+        EqualsMatcher(String filterText)
         {
-            super(filterText, comparisonValue);
+            super(filterText);
         }
 
         @Override
@@ -136,6 +135,119 @@ public class AlternativesStringFilter
 
     }
 
+    interface NumericalComparison
+    {
+        boolean matches(double value, double filterValue);
+    }
+
+    enum ComparisonKind implements NumericalComparison
+    {
+        LT("<")
+        {
+            public boolean matches(double value, double filterValue)
+            {
+                return value < filterValue;
+            }
+        },
+        GT(">")
+        {
+            public boolean matches(double value, double filterValue)
+            {
+                return value > filterValue;
+            }
+        },
+        LE("<=")
+        {
+            public boolean matches(double value, double filterValue)
+            {
+                return value <= filterValue;
+            }
+        },
+        GE(">=")
+        {
+            public boolean matches(double value, double filterValue)
+            {
+                return value >= filterValue;
+            }
+        },
+        EQ("=")
+        {
+            public boolean matches(double value, double filterValue)
+            {
+                return value == filterValue;
+            }
+        };
+
+        private final String operator;
+
+        ComparisonKind(String operator)
+        {
+            this.operator = operator;
+        }
+
+        public String getOperator()
+        {
+            return operator;
+        }
+
+    }
+
+    private static Map<String, ComparisonKind> comparisonKindByOperator =
+            new HashMap<String, ComparisonKind>();
+
+    static
+    {
+        for (ComparisonKind comparisonKind : ComparisonKind.values())
+        {
+            comparisonKindByOperator.put(comparisonKind.operator, comparisonKind);
+        }
+    }
+
+    static class NumericMatcher implements Matcher
+    {
+        protected final double filterValue;
+
+        private NumericalComparison comparison;
+
+        NumericMatcher(NumericalComparison comparison, double filterValue)
+        {
+            this.filterValue = filterValue;
+            this.comparison = comparison;
+        }
+
+        private boolean doMatch(double value)
+        {
+            return comparison.matches(value, filterValue);
+        }
+
+        public boolean matches(String value)
+        {
+            try
+            {
+                Double d = Double.parseDouble(value);
+                return doMatch(d);
+            } catch (NumberFormatException ex)
+            {
+                return false;
+            }
+        }
+    }
+
+    static class NegationMatcher implements Matcher
+    {
+        private Matcher delegate;
+
+        NegationMatcher(Matcher delegate)
+        {
+            this.delegate = delegate;
+        }
+
+        public boolean matches(String value)
+        {
+            return delegate.matches(value) == false;
+        }
+    }
+
     /**
      * Sets a new filter <var>value</var>.
      */
@@ -144,29 +256,74 @@ public class AlternativesStringFilter
         alternatives.clear();
         for (String s : StringUtils.tokenize(value))
         {
-            final boolean comparisonValue = (s.startsWith(PREFIX_NOT) == false);
-            if (comparisonValue == false)
+            final boolean negateValue = s.startsWith(PREFIX_NOT);
+            if (negateValue)
             {
                 s = s.substring(1);
             }
-            if (isStartAnchored(s))
-            {
-                if (isEndAnchored(s))
-                {
-                    alternatives.add(new EqualsMatcher(s.substring(1, s.length() - 1),
-                            comparisonValue));
-                } else
-                {
-                    alternatives.add(new StartAnchorMatcher(s.substring(1), comparisonValue));
-                }
-            } else if (isEndAnchored(s))
-            {
-                alternatives.add(new EndAnchorMatcher(s.substring(0, s.length() - 1),
-                        comparisonValue));
+            Matcher matcher = tryGetNumericMatcher(s);
+            if (matcher == null)
+            {
+                matcher = getStringMatcher(negateValue ? s.substring(1) : s);
+            }
+            if (negateValue)
+            {
+                matcher = new NegationMatcher(matcher);
+            }
+            alternatives.add(matcher);
+        }
+    }
+
+    private Matcher tryGetNumericMatcher(String s)
+    {
+        if (s.length() < 2)
+        {
+            return null;
+        }
+        if ("<>=".indexOf(s.charAt(0)) > -1)
+        {
+            int operatorLength = (s.charAt(1) == '=') ? 2 : 1;
+            String operator = s.substring(0, operatorLength);
+            String filterValue = s.substring(operatorLength);
+            ComparisonKind comparisonKindOrNull = tryGetComparisonKind(operator);
+            if (comparisonKindOrNull == null)
+            {
+                return null;
+            }
+            try
+            {
+                double dobuleValue = Double.parseDouble(filterValue);
+                return new NumericMatcher(comparisonKindOrNull, dobuleValue);
+            } catch (NumberFormatException e)
+            {
+                return null;
+            }
+        }
+        return null;
+    }
+
+    private ComparisonKind tryGetComparisonKind(String operator)
+    {
+        return comparisonKindByOperator.get(operator);
+    }
+
+    private Matcher getStringMatcher(String s)
+    {
+        if (isStartAnchored(s))
+        {
+            if (isEndAnchored(s))
+            {
+                return new EqualsMatcher(s.substring(1, s.length() - 1));
             } else
             {
-                alternatives.add(new ContainsMatcher(s, comparisonValue));
+                return new StartAnchorMatcher(s.substring(1));
             }
+        } else if (isEndAnchored(s))
+        {
+            return new EndAnchorMatcher(s.substring(0, s.length() - 1));
+        } else
+        {
+            return new ContainsMatcher(s);
         }
     }
 
@@ -198,4 +355,5 @@ public class AlternativesStringFilter
         }
         return false;
     }
+
 }
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/shared/basic/AlternativesStringFilterTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/shared/basic/AlternativesStringFilterTest.java
index 8d3936943b127c34323fb1bc3c59003c8923003a..0d20af51193178cf5ac9e50c2d8a82fab174c104 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/shared/basic/AlternativesStringFilterTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/shared/basic/AlternativesStringFilterTest.java
@@ -29,7 +29,7 @@ import org.testng.annotations.Test;
 public class AlternativesStringFilterTest
 {
 
-    private final AlternativesStringFilter prepare(String value)
+    private static final AlternativesStringFilter prepare(String value)
     {
         final AlternativesStringFilter filter = new AlternativesStringFilter();
         filter.setFilterValue(value);
@@ -309,4 +309,148 @@ public class AlternativesStringFilterTest
         assertFalse(filter.passes("start !^middle$ end"));
     }
 
+    // numeric
+
+    @Test
+    public void testNumericMatch()
+    {
+        final AlternativesStringFilter integerFilter = prepare("<10");
+        assertTrue(integerFilter.passes("5"));
+        assertTrue(integerFilter.passes("9.9"));
+        assertFalse(integerFilter.passes("10"));
+        assertFalse(integerFilter.passes("10.0"));
+        assertFalse(integerFilter.passes("10.1"));
+        assertFalse(integerFilter.passes("11"));
+        final AlternativesStringFilter realFilter = prepare("<9.8");
+        assertTrue(realFilter.passes("5"));
+        assertTrue(realFilter.passes("9.7"));
+        assertFalse(realFilter.passes("9.8"));
+        assertFalse(realFilter.passes("9.9"));
+        assertFalse(realFilter.passes("10"));
+    }
+
+    @Test
+    public void testAlternativeNumericMatch()
+    {
+        final AlternativesStringFilter filter = prepare("<10 >15 abc");
+        assertTrue(filter.passes("5"));
+        assertTrue(filter.passes("20"));
+        assertTrue(filter.passes("abcd"));
+        assertFalse(filter.passes("ab"));
+        assertFalse(filter.passes("11"));
+    }
+
+    @Test
+    public void testNonNumericMatch()
+    {
+        AlternativesStringFilter filter = prepare("<1>0");
+        assertTrue(filter.passes("<1>0"));
+        assertFalse(filter.passes("0.5"));
+
+        filter = prepare("==10");
+        assertTrue(filter.passes("==10"));
+        assertFalse(filter.passes("10"));
+
+        filter = prepare("<1a0");
+        assertTrue(filter.passes("<1a0"));
+        assertFalse(filter.passes("1a0"));
+
+        filter = prepare("\\<10");
+        assertTrue(filter.passes("<10"));
+        assertFalse(filter.passes("10"));
+    }
+
+    @Test
+    public void testLowerThan()
+    {
+        final AlternativesStringFilter filter = prepare("<10");
+        assertTrue(filter.passes("5"));
+        assertTrue(filter.passes("9.9"));
+
+        assertFalse(filter.passes("10"));
+        assertFalse(filter.passes("10.1"));
+        assertFalse(filter.passes("11"));
+
+        assertFalse(filter.passes("1abc"));
+        assertFalse(filter.passes("<10"));
+    }
+
+    @Test
+    public void testLowerEqual()
+    {
+        final AlternativesStringFilter filter = prepare("<=10");
+        assertTrue(filter.passes("5"));
+        assertTrue(filter.passes("9.9"));
+        assertTrue(filter.passes("10"));
+
+        assertFalse(filter.passes("10.1"));
+        assertFalse(filter.passes("11"));
+
+        assertFalse(filter.passes("1abc"));
+        assertFalse(filter.passes("<=10"));
+    }
+
+    @Test
+    public void testGreaterThan()
+    {
+        AlternativesStringFilter filter = prepare(">10");
+        assertFalse(filter.passes("5"));
+        assertFalse(filter.passes("9.9"));
+        assertFalse(filter.passes("10"));
+
+        assertTrue(filter.passes("10.1"));
+        assertTrue(filter.passes("11"));
+
+        assertFalse(filter.passes("1abc"));
+        assertFalse(filter.passes(">10"));
+    }
+
+    @Test
+    public void testGreaterEqual()
+    {
+        AlternativesStringFilter filter = prepare(">=10");
+        assertFalse(filter.passes("5"));
+        assertFalse(filter.passes("9.9"));
+
+        assertTrue(filter.passes("10"));
+        assertTrue(filter.passes("10.1"));
+        assertTrue(filter.passes("11"));
+
+        assertFalse(filter.passes("1abc"));
+        assertFalse(filter.passes(">=10"));
+    }
+
+    @Test
+    public void testEqual()
+    {
+        AlternativesStringFilter filter = prepare("=10.3");
+        assertFalse(filter.passes("5"));
+        assertFalse(filter.passes("9.9"));
+
+        assertTrue(filter.passes("10.3"));
+
+        assertFalse(filter.passes("10.33"));
+        assertFalse(filter.passes("11"));
+
+        assertFalse(filter.passes("1abc"));
+        assertFalse(filter.passes("=10.3"));
+    }
+
+    @Test
+    public void testNotEqual()
+    {
+        AlternativesStringFilter filter = prepare("!=10.3");
+        assertTrue(filter.passes("5"));
+        assertTrue(filter.passes("9.9"));
+
+        assertFalse(filter.passes("10.3"));
+
+        assertTrue(filter.passes("10.33"));
+        assertTrue(filter.passes("11"));
+
+        assertTrue(filter.passes("1abc"));
+        assertTrue(filter.passes("=10.3"));
+        assertTrue(filter.passes("!=10.3"));
+    }
+
 }