コード例 #1
0
        public int CompareTo(BPlusString bplusValue, KeywordMatchMode matchMode, bool ignoreCase)
        {
            if (String.IsNullOrEmpty(bplusValue.Value))
            {
                return(-1);
            }

            switch (matchMode)
            {
            case KeywordMatchMode.Contains:
                // we return 1 on no match so matching continues
                if (ignoreCase)
                {
                    return(bplusValue.Value.ToLower().Contains(_value.ToLower()) ? 0 : 1);
                }
                else
                {
                    return(bplusValue.Value.Contains(_value) ? 0 : 1);
                }

            case KeywordMatchMode.EndsWith:
                // we return 1 on no match so matching continues
                if (ignoreCase)
                {
                    return(bplusValue.Value.ToLower().EndsWith(_value.ToLower()) ? 0 : 1);
                }
                else
                {
                    return(bplusValue.Value.EndsWith(_value) ? 0 : 1);
                }

            case KeywordMatchMode.ExactMatch:
                return(String.Compare(_value, bplusValue.Value, ignoreCase, CultureInfo.CurrentCulture));

            case KeywordMatchMode.StartsWith:
                // we return 1 on no match so matching continues
                if (ignoreCase)
                {
                    if (bplusValue.Value.ToLower().StartsWith(_value.ToLower()))
                    {
                        return(0);
                    }
                }
                else
                {
                    if (bplusValue.Value.StartsWith(_value))
                    {
                        return(0);
                    }
                }

                // we get here, this value doesn't start with the given one.
                // keep checking -- but determine which direction to check
                // since we're doing a startswith, we need to determine which way to go
                return(String.Compare(_value, bplusValue.Value, ignoreCase, CultureInfo.CurrentCulture));

            default:
                throw new NotImplementedException(getDisplayMember("CompareTo", "Missing case in switch() in BPlusString.CompareTo()"));
            }
        }
コード例 #2
0
ファイル: BPlusInt.cs プロジェクト: radtek/genebank-gg_server
        public int CompareTo(BPlusInt bplusValue, KeywordMatchMode matchMode, bool ignoreCase)
        {
            int value = bplusValue.Value;

            if (_value < value)
            {
                return(-1);
            }
            else if (_value > value)
            {
                return(1);
            }
            else
            {
                return(0);
            }
        }
コード例 #3
0
        public List <KeywordMatch <TKey, TValue> > Update(TKey keyword, KeywordMatchMode matchMode, TValue newValue, UpdateMode updateMode)
        {
            List <KeywordMatch <TKey, TValue> > matches = new List <KeywordMatch <TKey, TValue> >();

            try {
                BPlusTree <TKey, TValue> .LogInfo("Begin updating keyword '" + keyword.ToString() + "'");

                this.performSearch(keyword, matchMode, false, false, matches);
                foreach (KeywordMatch <TKey, TValue> match in matches)
                {
                    match.Node.Values[match.Index].Update(newValue, updateMode);
                    match.Node.Write();
                }
            } finally {
                BPlusTree <TKey, TValue> .LogInfo("End updating keyword '" + keyword.ToString() + "'");
            }
            return(matches);
        }
コード例 #4
0
        public List <KeywordMatch <TKey, TValue> > Search(TKey keyword, KeywordMatchMode matchMode, bool ignoreCase)
        {
            List <KeywordMatch <TKey, TValue> > matches = new List <KeywordMatch <TKey, TValue> >();

            // Contains and EndsWith are special cases -- we index keywords from the leftmost data.
            // So to support those, we have essentially doa full leaf traversal.
            switch (matchMode)
            {
            case KeywordMatchMode.Contains:
                if (keyword.ToString().Length < Toolkit.ToInt32("SearchEngineMinimumQueryLengthForContains", 3))
                {
                    // don't let them do a 'contains' on something less than 2 chars, that will kill the server...
                    throw new InvalidOperationException(getDisplayMember("Search{contains}", "Invalid query.  Please lengthen your search criteria."));
                }
                else
                {
                    // ignore the tree, just traverse all leaves and all keywords in each leaf
                    foreach (BPlusTreeLeafNode <TKey, TValue> node in Tree.TraverseLeaves())
                    {
                        node.performSearch(keyword, matchMode, ignoreCase, false, matches);
                    }
                }
                break;

            case KeywordMatchMode.EndsWith:
                // ignore the tree, just traverse all leaves and all keywords in each leaf
                foreach (BPlusTreeLeafNode <TKey, TValue> node in Tree.TraverseLeaves())
                {
                    node.performSearch(keyword, matchMode, ignoreCase, false, matches);
                }
                break;

            default:
                // follow the index tree
                this.performSearch(keyword, matchMode, ignoreCase, false, matches);
                break;
            }

            return(matches);
        }
コード例 #5
0
        protected internal override void performSearch(TKey keyword, KeywordMatchMode matchMode, bool ignoreCase, bool returnLeafIfNotFound, List <KeywordMatch <TKey, TValue> > matches)
        {
            try {
                BPlusTree <TKey, TValue> .LogInfo("Begin performSearch node=" + this.ToString() + " keyword=" + keyword.ToString() + ", returnLeafIfNotFound=" + returnLeafIfNotFound);

                int childIndex = ChildLocations.Count - 1;

                // given a keyword, drill until the containing leaf node is found (return null when not found)
                if (matchMode == KeywordMatchMode.Contains || matchMode == KeywordMatchMode.EndsWith)
                {
                    // Contains and EndsWith must check all leaf nodes since the data is ordered alphabetically
                    // left-to-right.  So we can skip checking keywords because we know we need to end up at the leftmost leaf node
                    childIndex = 0;
                }
                else
                {
                    for (short i = 0; i < Keywords.Count; i++)
                    {
                        int compared = keyword.CompareTo(Keywords[i], matchMode, ignoreCase);
                        if (compared < 0)
                        {
                            // given keyword is smaller than this entry.
                            // follow the left child.
                            childIndex = i;
                            break;
                        }
                        else if (compared == 0)
                        {
                            if (matchMode == KeywordMatchMode.StartsWith)
                            {
                                // special case!  startswith doesn't mean there aren't more values to the left.
                                // so, we go left instead of right.
                                childIndex = i;
                            }
                            else
                            {
                                // given keyword is == this entry.
                                // follow right child.
                                childIndex = i + 1;
                            }
                            break;
                        }
                        else
                        {
                            // keep checking...
                        }
                    }
                }



                // either we found the proper index, or we ran out of keywords and the rightmost index is the proper index.
                // read in that child, split it if needed (if we're inserting), and search down that child
                BPlusTreeNode <TKey, TValue> child = BPlusTreeNode <TKey, TValue> .Read(this.Tree, this, ChildLocations[childIndex]);

                if (!returnLeafIfNotFound)
                {
                    // just continue the search down the child. if the node is full or not makes no difference -- they don't want us
                    // to return the leaf if it's not found anyway.
                    child.performSearch(keyword, matchMode, ignoreCase, returnLeafIfNotFound, matches);
                }
                else
                {
                    if (!child.IsFull)
                    {
                        // just continue the search down the child. we might have to perform an insert somewhere down the line,
                        // but there's still room in this particular node so we shouldn't split it.
                        child.performSearch(keyword, matchMode, ignoreCase, returnLeafIfNotFound, matches);
                    }
                    else
                    {
                        // child node is full and they want us to return a node even if not found -- they're inserting.
                        // split the child, then continue the search down the appropriate one

                        // NOTE: this does pre-emptive node splits -- meaning we split on the way down instead of
                        //       splitting on the way back up.  this is common practice to help increase concurrency.
                        int newKeywordIndex = 0;
                        BPlusTreeNode <TKey, TValue> newChild = this.SplitChild(child, out newKeywordIndex);

                        int compared = keyword.CompareTo(Keywords[newKeywordIndex], matchMode, ignoreCase);
                        if (compared < 0)
                        {
                            // new keyword is less than the keyword that was just copied/pushed into the parent (current) node.
                            // that new keyword belongs in the original child (left child)
                            child.performSearch(keyword, matchMode, ignoreCase, returnLeafIfNotFound, matches);
                        }
                        else
                        {
                            // keep checking...
                            newChild.performSearch(keyword, matchMode, ignoreCase, returnLeafIfNotFound, matches);
                        }
                    }
                }
            } finally {
                BPlusTree <TKey, TValue> .LogInfo("End performSearch node=" + this.ToString() + " keyword=" + keyword.ToString() + ", returnLeafIfNotFound=" + returnLeafIfNotFound);
            }
        }
コード例 #6
0
 //List<BPlusTreeLeafNode<TKey, TValue>> foundNodes,
 protected internal abstract void performSearch(TKey keyword, KeywordMatchMode matchMode, bool ignoreCase, bool returnLeafIfNotFound, List <KeywordMatch <TKey, TValue> > matches);
コード例 #7
0
        protected internal override void performSearch(TKey keyword, KeywordMatchMode matchMode, bool ignoreCase, bool returnLeafIfNotFound, List <KeywordMatch <TKey, TValue> > matches)
        {
            // given a keyword, spin until the keyword is found (return null when not found)
            short lastMatchIndex = -2;

            for (short i = 0; i < Keywords.Count; i++)
            {
                int compared = keyword.CompareTo(Keywords[i], matchMode, ignoreCase);
                if (compared < 0)
                {
                    // given keyword is smaller than this entry.
                    // means we're done looking in this leaf.
                    // if we didn't find anything and the caller said to return a leaf even if nothing was found, append this leaf
                    if (returnLeafIfNotFound && (matches.Count == 0 || matches[matches.Count - 1].Node != this))
                    {
                        // add this node as containing the hit even though it doesn't (so the value can be inserted)
                        // add this keyword as matching -- so they know where at in the node to insert their new item
                        matches.Add(new KeywordMatch <TKey, TValue> {
                            Index = i, Keyword = Keywords[i], Value = default(TValue), Node = this
                        });
                    }

                    return;
                }
                else if (compared == 0)
                {
                    // found keyword!
                    // add this node if it's not already in the list
                    // we may have multiple hits, so don't return yet.
                    // just add it to the list of matches.
                    matches.Add(new KeywordMatch <TKey, TValue> {
                        Index = i, Keyword = Keywords[i], Value = Values[i], Node = this
                    });
                    lastMatchIndex = i;
                }
                else
                {
                    // compared > 0
                    // given keyword is larger than this entry.
                    // keep checking.
                }
            }



            var inspectRightLeaf = false;

            switch (matchMode)
            {
            //case KeywordMatchMode.Contains:
            //case KeywordMatchMode.EndsWith:
            //    // data isn't stored in this order, so we always check the node (assuming there is one)
            //    inspectRightLeaf = true;
            //    break;
            case KeywordMatchMode.ExactMatch:
                // nothing more to do -- if the exact match occurred in this node, it won't occur in another node.
                break;

            case KeywordMatchMode.StartsWith:
            case KeywordMatchMode.Contains:
            case KeywordMatchMode.EndsWith:
                if (lastMatchIndex == Keywords.Count - 1)
                {
                    // last keyword matched, next leaf might have info in it.
                    inspectRightLeaf = true;
                }
                break;
            }



            if (inspectRightLeaf)
            {
                var nextLeaf = BPlusTreeLeafNode <TKey, TValue> .Read(this.Tree, null, this.RightSiblingLocation) as BPlusTreeLeafNode <TKey, TValue>;

                if (nextLeaf != null)
                {
                    // we're not on the rightmost node, inspect the next one
                    nextLeaf.performSearch(keyword, matchMode, ignoreCase, returnLeafIfNotFound, matches);
                }
                else
                {
                    // we get here, no more leaves exist.
                    // just return, the matches collection is filled properly already.
                }
            }
            else
            {
                // we get here, it was bigger than our biggest keyword
                // Since we're a leaf, it doesn't exist.
                if (returnLeafIfNotFound)
                {
                    // add this keyword as matching -- so they know where at in the node to insert their new item (note Index = Keywords.Count, so it'll be tacked on the end)
                    matches.Add(new KeywordMatch <TKey, TValue> {
                        Index = Keywords.Count, Keyword = default(TKey), Value = default(TValue), Node = this
                    });
                }
            }
        }
コード例 #8
0
        /// <summary>
        /// Performs a search for the given keyword using the given matchMode/ignoreCase.  For each item that matches, the callback is called, passing the current node, keyword offset, and the given additionalData with it.  This allows us to reuse the somewhat complex search code for searching and updating.
        /// </summary>
        /// <param name="keyword"></param>
        /// <param name="matchMode"></param>
        /// <param name="ignoreCase"></param>
        /// <param name="callback"></param>
        /// <param name="additionalData"></param>
        private void performSearch(string keyword, KeywordMatchMode matchMode, bool ignoreCase, SearchCallback callback, object additionalData)
        {
            int i        = 0;
            int compared = -1;

            // NOTE: We have the switch and as many of the if statements outside the loops as we can so we minimize branching within the loops.
            //       We'll be spinning through possibly millions of times so we're sacrificing cleaner, more intuitive code for performance here

            switch (matchMode)
            {
            case KeywordMatchMode.ExactMatch:
                // exact match.  using String.Compare instead of == allows us to jump out as soon as
                // we find a string "greater than" the search keyword.  If we just used ==, we'd have to always compare the entire
                // set of _keywords in this node if none was ever found.  Since once we find a match we stop, it's okay to put the IsLeaf check within the loop.

                // ExactMatch, regardless of Leafiness, regardless of case sensitivity
                while (i < KeywordCount && compared < 1)
                {
                    compared = String.Compare(Keywords[i], keyword, ignoreCase, CultureInfo.CurrentUICulture);
                    if (compared == 0)
                    {
                        // found our exact match
                        if (IsLeaf)
                        {
                            callback(this, i, additionalData);

                            // there may be multiple entries for a given keyword (unlikely, but possible)
                            // so do NOT jump out.
                        }
                        else
                        {
                            // continue searching the associated child node...
                            BPlusTreeNode node = BPlusTreeNode.Read(_tree, ChildrenByteOffsets[i], true);
                            node.performSearch(keyword, matchMode, ignoreCase, callback, additionalData);
                            // since this node is not a leaf, this means a given keyword will not appear more than once.
                            // so once we drill down, we're done.
                            return;
                        }
                    }
                    else if (compared > 0)
                    {
                        // this keyword is bigger than ours -- i.e. we know it's not in this node.
                        // if we're not a leaf, drill down...
                        if (!IsLeaf)
                        {
                            // continue searching the associated child node...
                            BPlusTreeNode node = BPlusTreeNode.Read(_tree, ChildrenByteOffsets[i], true);
                            node.performSearch(keyword, matchMode, ignoreCase, callback, additionalData);
                        }
                        // we've already passed where it could be an exact match in this node. jump out.
                        return;
                    }
                    else
                    {
                        // this keyword is "less than" our search keyword.  keep looking in this node.
                    }
                    i++;
                }
                if (!IsLeaf && i == KeywordCount)
                {
                    // we ran out of keywords to compare against -- means
                    // all keywords in this node are "less than" than our search keyword.
                    // if there's a right child, inspect it.
                    BPlusTreeNode node = BPlusTreeNode.Read(_tree, ChildrenByteOffsets[i], true);
                    node.performSearch(keyword, matchMode, ignoreCase, callback, additionalData);
                }
                break;

            case KeywordMatchMode.StartsWith:

                if (IsLeaf)
                {
                    // StartsWith, IsLeaf, regardless of case sensitivity (case sensitivity is handled by comparisonType variable)

                    while (i < KeywordCount)
                    {
                        if (Keywords[i].StartsWith(keyword, ignoreCase, CultureInfo.CurrentUICulture))
                        {
                            callback(this, i, additionalData);
                            // since this is a startswith (i.e. fuzzy on right)
                            // we should just inspect the entire node (do not jump out)
                        }
                        i++;
                    }
                }
                else
                {
                    // StartsWith, Is NOT Leaf, regardless of case sensitivity (case sensitivity is handled by comparisonType variable)

                    while (i < KeywordCount)
                    {
                        if (Keywords[i].StartsWith(keyword, ignoreCase, CultureInfo.CurrentUICulture))
                        {
                            BPlusTreeNode node = BPlusTreeNode.Read(_tree, ChildrenByteOffsets[i], true);
                            node.performSearch(keyword, matchMode, ignoreCase, callback, additionalData);
                            // since this is a startswith (i.e. fuzzy on right)
                            // we should just inspect the entire node (do not jump out)
                        }
                        else if (String.Compare(Keywords[i], keyword, ignoreCase, CultureInfo.CurrentUICulture) > 0)
                        {
                            // this keyword doesn't start with our search keyword, but it is "greater than" it.
                            // continue searching children
                            BPlusTreeNode node = BPlusTreeNode.Read(_tree, ChildrenByteOffsets[i], true);
                            node.performSearch(keyword, matchMode, ignoreCase, callback, additionalData);
                            return;
                        }
                        i++;
                    }
                    if (i == KeywordCount && ChildrenByteOffsets[i] > 0)
                    {
                        // we ran off the end. inspect rightmost child.
                        BPlusTreeNode node = BPlusTreeNode.Read(_tree, ChildrenByteOffsets[i], true);
                        node.performSearch(keyword, matchMode, ignoreCase, callback, additionalData);
                        return;
                    }
                }
                break;

            case KeywordMatchMode.EndsWith:

                // Since our index is built by the beginning of the word, we essentially have to do an index scan.
                // we'll use the tree's TraverseLeaves() method to do this efficiently.

                foreach (BPlusTreeNode node in _tree.TraverseLeaves())
                {
                    for (int j = 0; j < node.KeywordCount; j++)
                    {
                        if (node.Keywords[j].EndsWith(keyword, ignoreCase, CultureInfo.CurrentUICulture))
                        {
                            // this does end with what we're looking for...
                            callback(node, j, additionalData);

                            // since this is a endswith (i.e. fuzzy on left)
                            // we should just inspect the entire node (do not jump out)
                        }
                    }
                }


                break;

            case KeywordMatchMode.Contains:

                // Since our index is built by the beginning of the word, we essentially have to do an index scan.
                // we'll use the tree's TraverseLeaves() method to do this efficiently.

                if (ignoreCase)
                {
                    // Contains, Case Insensitive, regardless of leafiness

                    keyword = keyword.ToLower();
                    foreach (BPlusTreeNode node in _tree.TraverseLeaves())
                    {
                        for (int j = 0; j < node.KeywordCount; j++)
                        {
                            if (node.Keywords[j].ToLower().Contains(keyword))
                            {
                                // this does contain what we're looking for...
                                callback(node, j, additionalData);
                                // since this is a endswith (i.e. fuzzy on left)
                                // we should just inspect the entire node (do not jump out)
                            }
                        }
                    }
                }
                else
                {
                    // Contains, Case Sensitive, regardless of leafiness

                    foreach (BPlusTreeNode node in _tree.TraverseLeaves())
                    {
                        for (int j = 0; j < node.KeywordCount; j++)
                        {
                            if (node.Keywords[j].Contains(keyword))
                            {
                                // this does contain what we're looking for...
                                callback(node, j, additionalData);
                                // since this is a endswith (i.e. fuzzy on left)
                                // we should just inspect the entire node (do not jump out)
                            }
                        }
                    }
                }
                break;
            }
        }
コード例 #9
0
 internal void Search(string keyword, KeywordMatchMode matchMode, bool ignoreCase, List <KeywordMatch> results)
 {
     // when a hit is found, calls searchHit passing the results so it may fill it
     performSearch(keyword, matchMode, ignoreCase, foundNodeInSearch, results);
 }