<p>When entering a question, stackoverflow presents you with a list of questions that it thinks likely to cover the same topic. I have seen similar features on other sites or in other programs, too (Help file systems, for example), but I've never programmed something like this myself. Now I'm curious to know what sort of algorithm one would use for that.</p>

<p>The first approach that comes to my mind is splitting the phrase into words and look for phrases containing these words. Before you do that, you probably want to throw away insignificant words (like 'the', 'a', 'does' etc), and then you will want to rank the results.</p>

<p>Hey, wait - let's do that for web pages, and then we can have a ... watchamacallit ... -  a "search engine", and then we can sell ads, and then ...</p>

<p>No, seriously, what are the common ways to solve this problem?</p>

[{'answer_id': 70656, 'author': 'Antti Rasinen', 'author_id': 8570, 'author_profile': 'https://Stackoverflow.com/users/8570', 'pm_score': 5, 'selected': True, 'text': '<p>One approach is the so called bag-of-words model.</p>\n\n<p>As you guessed, first you count how many times words appear in the text (usually called document in the NLP-lingo). Then you throw out the so called stop words, such as "the", "a", "or" and so on.</p>\n\n<p>You\'re left with words and word counts. Do this for a while and you get a comprehensive set of words that appear in your documents. You can then create an index for these words:\n"aardvark" is 1, "apple" is 2, ..., "z-index" is 70092. </p>\n\n<p>Now you can take your word bags and turn them into vectors. For example, if your document contains two references for aardvarks and nothing else, it would look like this:</p>\n\n<pre><code>[2 0 0 ... 70k zeroes ... 0].\n</code></pre>\n\n<p>After this you can count the "angle" between the two vectors with <a href="http://en.wikipedia.org/wiki/Dot_product" rel="noreferrer">a dot product</a>. The smaller the angle, the closer the documents are.</p>\n\n<p>This is a simple version and there other more advanced techniques. May the <a href="http://en.wikipedia.org/wiki/Document_classification" rel="noreferrer">Wikipedia be with you</a>.</p>\n'}, {'answer_id': 70708, 'author': 'Sergey Volegov', 'author_id': 9024, 'author_profile': 'https://Stackoverflow.com/users/9024', 'pm_score': 2, 'selected': False, 'text': "<p>From my (rather small) experience developing full-text search engines: I would look up questions which contain some words from query (in your case, query is your question).\nSure, noise words should be ignored and we might want to check query for 'strong' words like 'ASP.Net' to narrow down search scope.\nhttp://en.wikipedia.org/wiki/Index_(search_engine)#Inverted_indices'>Inverted indexes are commonly used to find questions with words we are interested in.</p>\n\n<p>After finding questions with words from query, we might want to calculate distance between words we are interested in in questions, so question with 'phrases similarity' text ranks higher than question with 'discussing similarity, you hear following phrases...' text.</p>\n"}, {'answer_id': 70929, 'author': 'Jorge Ferreira', 'author_id': 6508, 'author_profile': 'https://Stackoverflow.com/users/6508', 'pm_score': 2, 'selected': False, 'text': '<p>@Hanno you should try the Levenshtein distance algorithm. Given an input string <strong>s</strong> and a list of of strings <strong>t</strong> iterate for each string <strong>u</strong> in <strong>t</strong> and return the one with the minimum Levenshtein distance.</p>\n\n<p><a href="http://en.wikipedia.org/wiki/Levenshtein_distance" rel="nofollow noreferrer">http://en.wikipedia.org/wiki/Levenshtein_distance</a></p>\n\n<p>See a Java implementation example in <a href="http://www.javalobby.org/java/forums/t15908.html" rel="nofollow noreferrer">http://www.javalobby.org/java/forums/t15908.html</a></p>\n'}, {'answer_id': 72006, 'author': 'Tyler', 'author_id': 3561, 'author_profile': 'https://Stackoverflow.com/users/3561', 'pm_score': 2, 'selected': False, 'text': '<p>To augment the bag-of-words idea:</p>\n\n<p>There are a few ways you can also pay some attention to n-grams, strings of two or more words kept in order.  You might want to do this because a search for "space complexity" is much more than a search for things with "space" AND "complexity" in them, since the meaning of this phrase is more than the sum of its parts; that is, if you get a result that talks about the complexity of outer space and the universe, this is probably not what the search for "space complexity" really meant.</p>\n\n<p>A key idea from natural language processing here is that of <a href="http://en.wikipedia.org/wiki/Mutual_information" rel="nofollow noreferrer">mutual information</a>, which allows you (algorithmically) to judge whether or not a phrase is really a specific phrase (such as "space complexity") or just words which are coincidentally adjacent.  Mathematically, the main idea is to ask, probabilistically, if these words appear next to each other more often than you would guess by their frequencies alone.  If you see a phrase with a high mutual information score in your search query (or while indexing), you can get better results by trying to keep these words in sequence.</p>\n'}, {'answer_id': 73842199, 'author': 'Subhradeep Biswas', 'author_id': 20080779, 'author_profile': 'https://Stackoverflow.com/users/20080779', 'pm_score': 0, 'selected': False, 'text': "<p>Here is the bag of words solution with tfidfvectorizer in python 3</p>\n<pre><code>#from sklearn.feature_extraction.text import CountVectorizer\nfrom sklearn.feature_extraction.text import TfidfVectorizer\nimport nltk\nnltk.download('stopwords')\ns=set(stopwords.words('english'))\n\ntrain_x_cleaned = []\nfor i in train_x:\n    sentence = filter(lambda w: not w in s,i.split(&quot;,&quot;))\n    train_x_cleaned.append(' '.join(sentence))\n\nvectorizer = TfidfVectorizer(binary=True)\ntrain_x_vectors = vectorizer.fit_transform(train_x_cleaned)\n\nprint(vectorizer.get_feature_names_out())\nprint(train_x_vectors.toarray())\n\nfrom sklearn import svm\n\nclf_svm = svm.SVC(kernel='linear')\nclf_svm.fit(train_x_vectors, train_y)\n\ntest_x = vectorizer.transform([&quot;test phrase 1&quot;, &quot;test phrase 2&quot;, &quot;test phrase 3&quot;])\nprint (type(test_x))\nclf_svm.predict(test_x)\n</code></pre>\n"}]
['https://Stackoverflow.com/questions/70560', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/2077/']