diff --git a/app/models.py b/app/models.py
index 8da58c0f7d50fdf6b38dcb425815e54c03c32f87..dc89da1638d72f83bab73aab3be1dcf3efc3befe 100644
--- a/app/models.py
+++ b/app/models.py
@@ -436,10 +436,37 @@ class SearchableMixin(object):
             search.remove_from_index(index, id)
         session._changes = None
 
+    @classmethod
+    def delete_index(cls, **kwargs):
+        """Delete the index of the class"""
+        current_app.logger.info(f"Delete the {cls.__tablename__} index")
+        search.delete_index(
+            cls.__tablename__ + current_app.config["ELASTICSEARCH_INDEX_SUFFIX"],
+            **kwargs,
+        )
+
+    @classmethod
+    def create_index(cls, **kwargs):
+        """Create the index of the class"""
+        if hasattr(cls, "__mapping__"):
+            current_app.logger.info(f"Create the {cls.__tablename__} index")
+            search.create_index(
+                cls.__tablename__ + current_app.config["ELASTICSEARCH_INDEX_SUFFIX"],
+                cls.__mapping__,
+                **kwargs,
+            )
+        else:
+            current_app.logger.info(
+                f"No mapping defined for {cls.__tablename__}. No index created."
+            )
+
     @classmethod
     def reindex(cls):
         """Force to reindex all instances of the class"""
         current_app.logger.info(f"Force to re-index all {cls.__tablename__} instances")
+        # Ignore index_not_found_exception
+        cls.delete_index(ignore_unavailable=True)
+        cls.create_index()
         for obj in cls.query:
             search.add_to_index(
                 cls.__tablename__ + current_app.config["ELASTICSEARCH_INDEX_SUFFIX"],
@@ -577,6 +604,25 @@ class Item(CreatedMixin, SearchableMixin, db.Model):
             "model_id",
         ]
     }
+    __mapping__ = {
+        "created_at": {"type": "date", "format": "yyyy-MM-dd HH:mm"},
+        "updated_at": {"type": "date", "format": "yyyy-MM-dd HH:mm"},
+        "user": {"type": "keyword"},
+        "ics_id": {"type": "keyword"},
+        "serial_number": {"type": "keyword"},
+        "quantity": {"type": "long"},
+        "manufacturer": {"type": "keyword"},
+        "model": {"type": "keyword"},
+        "location": {"type": "keyword"},
+        "status": {"type": "keyword"},
+        "parent": {"type": "keyword"},
+        "children": {"type": "keyword"},
+        "macs": {"type": "keyword"},
+        "host": {"type": "keyword"},
+        "stack_member": {"type": "keyword"},
+        "history": {"enabled": False},
+        "comments": {"type": "text"},
+    }
 
     # WARNING! Inheriting id from CreatedMixin doesn't play well with
     # SQLAlchemy-Continuum. It has to be defined here.
@@ -1041,6 +1087,40 @@ class AnsibleGroup(CreatedMixin, db.Model):
 
 class Host(CreatedMixin, SearchableMixin, db.Model):
     __versioned__ = {}
+    __mapping__ = {
+        "created_at": {"type": "date", "format": "yyyy-MM-dd HH:mm"},
+        "updated_at": {"type": "date", "format": "yyyy-MM-dd HH:mm"},
+        "user": {"type": "keyword"},
+        "name": {"type": "keyword"},
+        "fqdn": {"type": "keyword"},
+        "is_ioc": {"type": "boolean"},
+        "device_type": {"type": "keyword"},
+        "model": {"type": "keyword"},
+        "description": {"type": "text"},
+        "items": {"type": "keyword"},
+        "interfaces": {
+            "properties": {
+                "id": {"enabled": False},
+                "created_at": {"type": "date", "format": "yyyy-MM-dd HH:mm"},
+                "updated_at": {"type": "date", "format": "yyyy-MM-dd HH:mm"},
+                "user": {"type": "keyword"},
+                "is_main": {"type": "boolean"},
+                "network": {"type": "keyword"},
+                "ip": {"type": "ip"},
+                "netmask": {"enabled": False},
+                "name": {"type": "keyword"},
+                "mac": {"type": "keyword"},
+                "host": {"type": "keyword"},
+                "cnames": {"type": "keyword"},
+                "domain": {"type": "keyword"},
+                "tags": {"type": "keyword"},
+                "device_type": {"type": "keyword"},
+                "model": {"type": "keyword"},
+            }
+        },
+        "ansible_vars": {"enabled": False},
+        "ansible_groups": {"type": "keyword"},
+    }
 
     # id shall be defined here to be used by SQLAlchemy-Continuum
     id = db.Column(db.Integer, primary_key=True)
diff --git a/app/search.py b/app/search.py
index e7ce5e0e33687986db4f9c2d7504ee7902a3012f..724208f9035c69d1b2b377f0e17bdcfda3f74ce6 100644
--- a/app/search.py
+++ b/app/search.py
@@ -12,6 +12,21 @@ This module implements the search interface.
 from flask import current_app
 
 
+def delete_index(index, **kwargs):
+    """Delete the given index"""
+    if not current_app.elasticsearch:
+        return
+    current_app.elasticsearch.indices.delete(index=index, **kwargs)
+
+
+def create_index(index, mapping, **kwargs):
+    """Create an index with the given mapping"""
+    if not current_app.elasticsearch:
+        return
+    body = {"mappings": {"_doc": {"dynamic": "strict", "properties": mapping}}}
+    current_app.elasticsearch.indices.create(index=index, body=body, **kwargs)
+
+
 def add_to_index(index, body):
     """Add a document to an index"""
     if not current_app.elasticsearch:
diff --git a/app/utils.py b/app/utils.py
index bda66893cc8a93ee119fbe6e200c6c33ac5873b7..7362ca19c977bff3c1c7a10e520ff170d00690bb 100644
--- a/app/utils.py
+++ b/app/utils.py
@@ -309,15 +309,11 @@ def retrieve_data_for_datatables(values, model):
     else:
         name = values.get(f"columns[{order_column}][data]")
         order_dir = values.get("order[0][dir]", "asc")
-        # For all fields of type text, sorting should be done
-        # on .keyword in elasticsearch
-        # quantity (in items table) is of type integer
-        # It's hard-coded here for now. If needed we can try to find a
-        # generic way to find this information.
-        if name == "quantity":
-            sort = f"{name}:{order_dir}"
-        else:
-            sort = f"{name}.keyword:{order_dir}"
+        # Sorting can be done directly on all fields of type
+        # keyword/date/long
+        # If we want to sort on fields of type text, we should
+        # add an extra .keyword field!
+        sort = f"{name}:{order_dir}"
     instances, nb_filtered = model.search(
         search, page=page, per_page=per_page, sort=sort
     )
diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py
index 4b0fa78dd193d7e18a0438b4d0c91b09fabdbfd7..048817eaaec6af5c9b160d878331bf7942b0083f 100644
--- a/tests/functional/conftest.py
+++ b/tests/functional/conftest.py
@@ -15,7 +15,7 @@ from pytest_factoryboy import register
 from flask_ldap3_login import AuthenticationResponse, AuthenticationResponseStatus
 from app.factory import create_app
 from app.extensions import db as _db
-from app.models import SearchableMixin
+from app.models import SearchableMixin, Host, Item
 from . import common, factories
 
 register(factories.UserFactory)
@@ -124,6 +124,10 @@ def session(db, request):
     db.event.listen(session(), "after_commit", SearchableMixin.after_commit)
     db.session = session
 
+    # Create the elasticsearch indices
+    Item.create_index()
+    Host.create_index()
+
     yield session
 
     # ELASTICSEARCH_INDEX_SUFFIX is set to "-test"