def cluster(self, messages, appDatas):
        if messages is None:
            raise TypeError("Messages cannot be None")
        if appDatas is None:
            raise TypeError("AppDatas cannot be None")
        if len(messages) == 0:
            raise TypeError("There should be at least one message.")
        if len(appDatas) == 0:
            raise TypeError("There should be at least one applicative data.")

        for m in messages:
            if not isinstance(m, AbstractMessage):
                raise TypeError("At least one message ({0}) is not an AbstractMessage.".format(str(m)))
        for appData in appDatas:
            if not isinstance(appData, ApplicativeData):
                raise TypeError("At least one applicative data ({0}) is not an instance of ApplicativeData.".format(str(appData)))

        labels = dict()
        for appData in appDatas:
            labels[appData.value] = appData.name

        idMessages = dict()
        for message in messages:
            idMessages[message.id] = message

        messagesPerAppData = dict()
        for message in messages:
            messagesPerAppData[message] = set()

        searchEngine = SearchEngine()

        searchResults = searchEngine.searchDataInMessages([appData.value for appData in appDatas], messages, inParallel=True, dataLabels=labels)
        for result in searchResults:
            searchTask = result.searchTask
            message = searchTask.properties['message']
            label = searchTask.properties['label']
            if label not in list(labels.values()):
                raise ValueError("Found label ({0}) in a result cannot be identified in the original list of searched labels.".format(label))
            if message.id not in list(idMessages.keys()):
                raise ValueError("Found message ({0}) cannot be identified in the original list of searched messages.".format(message.id))
            messagesPerAppData[idMessages[message.id]].add(label)

        # Build clusters
        clusters = dict()
        for message, labelsInMessage in list(messagesPerAppData.items()):
            strAppDatas = ';'.join(sorted(labelsInMessage))
            if len(strAppDatas) == 0:
                strAppDatas = None
            if strAppDatas in list(clusters.keys()):
                clusters[strAppDatas].append(message)
            else:
                clusters[strAppDatas] = [message]

        # Build Symbols
        symbols = [Symbol(name=strAppDatas, messages=msgs) for strAppDatas, msgs in list(clusters.items())]

        return symbols