/// <summary>
        /// Initializes a new instance of the <see cref="StringKeywordSuggestion"/> class.
        /// </summary>
        /// <param name="keywordValue">Sets value of keyword</param>
        /// <param name="sourceId">Id of the source that is creating this suggestion</param>
        /// <param name="sourceName">Optional id of the source. If not provided the name will be </param>
        public StringKeywordSuggestion(string keywordValue, Guid sourceId, string sourceName = "")
        {
            if (keywordValue.Trim().Equals(string.Empty))
            {
                throw new ArgumentException("KeywordValue should not be an empty string");
            }

            if (sourceId == null)
            {
                throw new ArgumentNullException("Source id is not set");
            }

            if (keywordValue.Equals(string.Empty))
            {
                throw new ArgumentException();
            }

            this.objectValue = new SimpleStringObject(keywordValue);
            this.sourceId = sourceId;
            this.sourceName = sourceName.Equals(string.Empty) ? this.sourceId.ToString() : this.sourceName = sourceName;
            this.rankValue = 1;
            this.relevance = -1;
        }
        /// <summary>
        /// Suggests description instances from the defined in Suggester sources based on one or more semantic objects
        /// </summary>
        /// <param name="semanticObjects">RDF based concrete semantic object</param>
        /// <param name="sourceFilter">if Null all sources are used, if set only those set are processed</param>
        /// <returns>Returns collection of suggested description objects (such as keywords, RDF statements, etc.)</returns>
        public List<ISuggestionInstance> GetSuggestions(ISemanticObject[] semanticObjects, Guid[] sourceFilter = null)
        {
            Dictionary<string, Tuple<ISuggestionInstance, double>> CombinedCollection = new Dictionary<string, Tuple<ISuggestionInstance, double>>();
            double maxRelevanceSum = 0;
            double minRelevanceValue = double.MaxValue;
            const string combinedSourceName = "Multiple sources";
            Guid combinedGuid = Guid.NewGuid();

            foreach (var nextSource in this.sources)
            {
                if (sourceFilter == null || sourceFilter.Contains(nextSource.Guid))
                {
                    foreach (var nextResult in nextSource.GetSuggestions(semanticObjects))
                    {
                        double combinedrelevance;
                        if (CombinedCollection.ContainsKey(nextResult.GetTextValue()))
                        {
                            var oldvalue = CombinedCollection[nextResult.GetTextValue()];
                            combinedrelevance = oldvalue.Item2 + nextResult.Relevance;

                            // HACK - think how this should be when RDF suggestions sources implemented. Should we flatter them like this or do something else.
                            var combinedResult = new StringKeywordSuggestion(nextResult.GetTextValue(), combinedGuid, combinedSourceName);
                            nextResult.Rank = nextResult.Rank + oldvalue.Item1.Rank;
                            CombinedCollection[nextResult.GetTextValue()] = new Tuple<ISuggestionInstance, double>(combinedResult, combinedrelevance);
                        }
                        else
                        {
                            combinedrelevance = nextResult.Relevance;
                            CombinedCollection.Add(nextResult.GetTextValue(), new Tuple<ISuggestionInstance, double>(nextResult, combinedrelevance));
                        }

                        if (combinedrelevance > maxRelevanceSum)
                        {
                            maxRelevanceSum = combinedrelevance;
                        }

                        if (combinedrelevance < minRelevanceValue)
                        {
                            minRelevanceValue = combinedrelevance;
                        }
                    }
                }
            }

            // now normalize relevance
            var readyList = new List<ISuggestionInstance>();
            foreach (var nextSuggestion in CombinedCollection)
            {
                // map 0...max to 0..100;
                double newrelevance = (maxRelevanceSum * nextSuggestion.Value.Item2 == 0) ? 0 : 100 / maxRelevanceSum * nextSuggestion.Value.Item2;
                var nextsuggestion = nextSuggestion.Value.Item1;
                nextsuggestion.Relevance = newrelevance;
                readyList.Add(nextsuggestion);
            }

            readyList.Sort(delegate (ISuggestionInstance x, ISuggestionInstance y)
            {
                return y.Relevance.CompareTo(x.Relevance); // descending sort
            });
            return readyList;
        }