淺談信息檢索

按:本文淺談信息檢索是什麼,爲何,怎麼作等問題,主要內容是Manning等人著的《信息檢索導論》前八張的讀書筆記php

問曰:信息檢索的定義是什麼?

答曰:html

根據《信息檢索導論》(Manning, Raghavan & Schütze, 2008)第一章:java

Information retrieval (IR) is finding material (usually documents) of an unstructured nature (usually text) that satisfies an information need from within large collections (usually stored on computers).python

翻譯過來的大白話,「信息檢索」是在一大堆非結構化的信息裏面(一般是文本),找到符合需求的信息。web

問曰: 爲何會產生信息檢索?

  • 或問曰: 信息檢索這門技術用在什麼地方?算法

  • 或問曰: 信息檢索的起源與演變過程是怎樣的?typescript

答曰:json

爲何須要信息檢索?最本源的緣由就是,信息太多,找不過來,須要有相應的技術和工具輔助。信息越多,咱們的需求越細緻,就越要使用高級的技術和工具。ubuntu

信息檢索技術起源於圖書館書籍管理。這不難理解,在計算機和互聯網出現之前,書籍就是信息的基本載體,圖書館就是信息的集中地。要在一本書籍中找到某個信息,好比「某個朝代發生的某件事情」,能夠人工把書本翻個遍,找出來這個信息,這並非難難事。但要在整個圖書館找到符合「某個朝代發生的某件事情」這個需求的信息,顯然是不可能一本書一本書地去翻。所以,對書籍進行分類,就是必須的。分類之後,咱們能夠到「歷史」這個類別裏找到這個朝代的書籍,再翻書查找。「分類」就是最簡單的信息管理手段,對信息分類,而後根據需求到特定的類別裏去找找信息,就是最簡單的信息檢索方法。數組

進入互聯網時代,計算機裏的文檔成爲了信息的主要載體,互聯網成爲了新時代的圖書館(互聯網本質上就是一個分佈式文檔系統)。天然而然地,分類方法在一開始也被應用到了互聯網文檔(主要是HTML文檔)的檢索上。而Yahoo!的成功案例也證實了分類方法在互聯網初期也是很是有用的。但隨着互聯網內容的爆炸性增加,分類方法也逐漸失效了。沒辦法,即使設置幾百個類別,每一個類別內的內容也太多了。因此Yahoo!逐漸沒落,而Google逐漸興起。畢竟Google表明的全文搜索方法不管在有效性仍是快捷性都比分類方法有優點。

至此,信息檢索的發展主要脈絡就是從圖書館書籍管理開始產生分類方法,而後在互聯網時代分類方法再也不適用,由此催生了全文檢索方法,更準確地說,是創建索引,用索引來作檢索的方法。

  • 什麼是索引?

索引,顧名思義,就是搜索的指引。任何可以指引咱們儘快搜索到咱們所求之物的東西,都是索引。若咱們把每一本書的書名、做者等信息記錄在案,找書時只要提供書名、做者等部分或所有信息,就能找到一本書。這種狀況下,書名、做者信息的記錄表就是索引。Google的全文檢索把每一篇文檔的每個詞記錄在案,造成了一個全面而龐大的索引,因此能比分類法更準確的找到信息。順帶一提,這種角度看,分類法實際上是索引法的特殊形式,由於類別也是一種索引。如此一來,用全文每一個詞作索引,和根據書本要義用類別作索引,孰優孰劣,就不難分別了。

問曰: 什麼是信息檢索?

  • 或問曰: 信息檢索的目標是什麼? 實現目標的基本流程如何?
  • 問曰: 信息檢索的基本任務是什麼? 其基本手段又是什麼?

答曰:

信息檢索的目標,或者說基本的任務,就是從一大堆信息中找到咱們須要的某部分信息。進一步,咱們縮小範圍,使之更加具體:信息檢索的目標是在一大堆文檔等非結構化信息中根據咱們的需求挑選出咱們須要的部分文檔。這其實就體如今Manning等人對信息檢索的定義中。

那麼,進行信息檢索的基本流程有哪些?或者說爲了達成信息檢索的任務,咱們要作哪些子任務?首先咱們總得先對咱們眼前的一大堆數據(在這裏特指文檔集),有一個清晰的認識。起碼要知道這個文檔集的規模如何,文檔由哪些語言寫成,若是是電子文檔,還要檢查一下編碼之類的,這樣咱們就能夠大概知道須要用什麼方案。而後就能夠創建索引,不管是類別,仍是全文詞項,又或是其餘的輔助指引工具,都是索引。最後還要實現檢索機制,好比制定一些圖書館借閱規定,或者開發一套計算機系統。

問曰: 目前最典型的信息檢索方案是怎樣的?

答曰(這一部分假定讀者掌握線性代數的基礎知識):

目前最經常使用最典型的信息檢索任務,恐怕就是對網聯網上的文檔作檢索了。而最典型的信息檢索方案,即是web搜索引擎。那麼web搜索引擎的工做原理又是怎樣的呢?

Google和百度等大公司都會有web採集器,不斷地、動態地從網上獲取web文檔(基本就是HTML文檔)。採集回來的文檔就是信息集,要在這麼一大堆文檔裏(一般是百億級規模)找出用戶須要的文檔,就須要索引了。

不過搜索引擎用到的索引到底長什麼樣?

咱們要根據關鍵詞把文檔找出來,也就是說要針對文檔中出現的每個詞給問你當創建索引。因此全文檢索用到的索引就是一個以詞爲行,文檔爲列的「詞-文檔表格」,確切的說是「詞-文檔矩陣」。

詞-文檔矩陣

上圖就是一個「詞-文檔矩陣」,圖中的行就是文檔中出現的詞,列就是文檔的名字(都是莎士比亞的做品)。圖中某行某列中的0表明該行的詞未曾出如今該列的文檔中,反之。所以「Antony」這個詞出如今了「Julius Caesar」這篇文檔中,而未曾出如今「Hamlet」中。 從這個矩陣能夠清晰看出哪些詞存在於哪些文檔中,這個就是全文搜索會用到的索引,到信息檢索裏的術語稱爲「倒排索引」。

要知道,互聯網上的文檔數量是百億級的,而其中包含的詞可能也要數十萬甚至上百萬(瞎猜的),總之比任何一步詞典收錄的詞都要多。這麼大的矩陣,實在是太過佔用空間了,哪怕是今天,計算機的內存都是寶貴資源啊。考慮到大規模文檔集和大規模詞表造成的「詞-文檔矩陣」中會有不少0存在,咱們就不難想到採用稀疏表示的方式來存儲這個矩陣。而上圖的索引也會變成下面的樣子。

倒排索引

圖中左邊是詞項,右邊則是文檔(編號)列表。「Brutus」對應的列表裏有一、二、4等號碼,意味着文檔一、文檔二、文檔4裏包含着「Brutus」這個詞。

那麼這個索引是怎麼構建出來的呢?

在建索引前確定要作一些預處理。常見的預處理可能會有識別文檔編碼(UTF-8?GBK?ASKII?),選用正確的解碼方式。而後就是分詞。英文等拉丁語系的文字詞與詞之間有間隔,因此還不算難,但也要注意不能把「United Kingdom」這樣的專有名詞切開。而對於漢語等東亞的語言文字,就須要特殊的分詞手段(好比條件隨機場、馬爾科夫鏈等)。分完詞後還沒完,通常還會把一些的都好、句號之類的符號去掉。最後可能還會考慮一下要不要把全部詞換成小寫,甚至進行詞根還原(把詞的動詞、名詞等各類形式統一映射到詞根)等詞項歸一化,使得用戶的查詢可以匹配到更多可能相關結果。

通過了編碼識別、分詞、大小寫轉換、詞項歸一化等一系列預處理,咱們把一個文檔轉換成詞項流(能夠當作由詞組成的數組),所以文檔集也就轉換成了詞項數組的集合。接下來咱們就能夠創建索引了。咱們能夠掃描一遍獲得的詞項流,獲得一個「詞-文檔ID」流,而後把詞項相同的元組合並,就獲得了下圖右面的倒排索引

係數矩陣形式倒排索引

Talk is cheap, show me your code!

​ —— Torvalds · Linus

下面是一段很簡單的python代碼,爲一個簡單的文檔集構建倒排索引

"""
inverted_index.py

Build a basic (naive) inverted index for a simple (naive) documents set
Please Run this script using Python3.x 
Tested under Python3.6, Win7 and Python3.5 ubuntu16.04
Author: Richy Zhu
Email: rickyzhu@foxmail.com
"""

import json
import re
from pprint import pprint

def clear_symbols(text):
    """remove symbols like commas, semi-commas
    """
    simbols = re.compile("[\s+\.\!\/_,$%^*()+\"\']+|[+——!,。?、~@#¥%……&*():]+")
    if type(text) is str:   
        processed_text = re.sub(simbols, ' ', text)
        return processed_text
    elif type(text) is list:
        return [re.sub(simbols, ' ', item) for item in text]
    else:
        raise TypeError("This function only accept str or list as argument")

def lowercase(text):
    """turn all the characters to be lowercase
    """
    if type(text) is str:
        return text.lower()
    elif type(text) is list:
        return [item.lower() for item in text]
    else:
        raise TypeError("This function only accept str or list as argument")

def tokenize(docs):
    token_stream = []
    for doc in docs:
        token_stream.append(doc.split())
    return token_stream

def preprocess(docs):
    """clear symbols, lowercase, tokenize, get clean tokenized docs
    """
    normalized_docs = lowercase(clear_symbols(docs))
    tokenized_docs = tokenize(normalized_docs)
    return tokenized_docs

def get_token_stream(tokenized_docs, docs_dict):
    """get (term-doc_id) stream
    """
    token_stream = []
    for doc_id in docs_dict:
        for term in tokenized_docs[doc_id]:
            token_stream.append((term, doc_id))
    return token_stream

def build_indices(tokenized_docs, docs_dict):
    """main function -- build invertex index
       assume that the documents set is small enough to be loaded into Memory
    """
    token_stream = get_token_stream(tokenized_docs, docs_dict)
    # pprint(token_stream)
    indices = {}

    for pair in token_stream:
        if pair[0] in indices:
            if pair[1] not in indices[pair[0]]:
                indices[pair[0]].append(pair[1])
        else:
            indices[pair[0]] = [pair[1]]
    return indices

if __name__ == "__main__":
    docs = [
        "hello world",
        "hello python", 
        "I love C, Java, Python, Typescript, and PHP",
        "use python to build inverted indices",
        "you and me are in one world"
        ]
    docs_dict = {
        0: "docs[0]",
        1: "docs[1]",
        2: "docs[3]",
        3: "docs[4]",
        4: "docs[5]"
    }
    tokenized_docs = preprocess(docs)
    # pprint(tokenized_docs)
    indices = build_indices(tokenized_docs, docs_dict)
    pprint(indices)

運行文件能夠獲得以下結果:

$ python3 inverted_index.py
{'and': [4],
 'are': [4],
 'build': [3],
 'hello': [0, 1],
 'i': [2],
 'in': [4],
 'indices': [3],
 'inverted': [3],
 'love': [2],
 'me': [4],
 'one': [4],
 'python': [1, 2, 3],
 'to': [3],
 'use': [3],
 'world': [0, 4],
 'you': [4]}

固然,上面的索引構建程序有一個假設:文檔規模不大,整個文檔集索引的構建過程均可以在內存裏完成。若是文檔集過大,就要將其分割成較小的塊,對每塊作構建索引的操做,而後把每個塊操做的結果(這一個塊的索引文件)合併起來獲得整個文檔集的索引。典型的算法有BSBI算法、SPIMI算法等。

如今咱們已經有一個索引了,但咱們怎麼去使用呢?

有了索引,就能夠很方便地找出咱們須要的文檔,最典型的的應用是布爾查詢。布爾查詢使用布爾運算符對查詢 關鍵詞進行鏈接,好比:

「信息 AND 檢索 AND 導論」, 這個查詢就是查找文中既包含「信息」,又包含「檢索」,還包含「導論」這三個關鍵詞的文檔。

「(python OR Java) NOT Ruby」,這個查詢就是查找文中包含「python」或包含「Java」,但不包含「Ruby」的文檔。

對於AND操做,只需在索引中找到每一個關鍵詞對應的的文檔ID列表,而後對文檔ID列表求交集,也就是找出全部列表中共有的文檔ID,那麼這些找出來的文檔就是用戶想要的文檔。OR的NOT操做再也不贅述。

直到如今,不少圖書館的檢索系統都還支持布爾查詢的操做(大多放在「高級查詢」功能裏面)。

可是下一個問題來了,布爾查詢使用到布爾操做符,並且其理論基礎是布爾代數。雖然說他們已經足夠簡單,但仍是要求用戶學習一點知識。並且布爾查詢的查詢表達式能夠至關複雜。並且查找出來的文檔雖然都與用戶的查詢相關,可是並不能按照類似程度來排序,只能根據發表日期等指標來排序。

那麼有沒有更加簡單有效的方法讓用戶輸入天然語言查詢(而非布爾表達式等有必定規則的查詢),獲得根據相關程度排序的文檔結果呢?

答案是向量空間模型

咱們的目標是把全部文檔和用戶查詢一塊兒轉化成向量(詞袋模型、if-idf權重),而後使用線性代數的方法來求得用戶查詢向量與全部文檔向量之間的類似度(餘弦類似度),進而獲得用戶查詢與全部文檔之間的相關程度。

要把向量空間模型應用於信息檢索,要關注三個重要概念:詞袋模型、TF-IDF、餘弦類似度

關於向量空間模型的文章整個互聯網滿大街都是,隨便百度一下都能找到許多好的入門文章。在此我摘引一篇文章的部分來介紹詞袋模型,資料來自bag-of-words模型入門

Bag-of-words模型是信息檢索領域經常使用的文檔表示方法

在信息檢索中,BOW模型假定對於一個文檔,忽略它的單詞順序和語法、句法等要素,將其僅僅看做是若干個詞彙的集合,文檔中每一個單詞的出現都是獨立的,不依賴於其它單詞是否出現。(是不關順序的)

也就是說,文檔中任意一個位置出現的任何單詞,都不受該文檔語意影響而獨立選擇的。那麼究竟是什麼意思呢?那麼給出具體的例子說明:

例子

Wikipedia[1]上給出了以下例子:

John likes to watch movies. Mary likes too.
John also likes to watch football games.

根據上述兩句話中出現的單詞, 咱們能構建出一個字典 (dictionary):

{
  "John": 1, 
  "likes": 2, 
  "to": 3, 
  "watch": 4, 
  "movies": 5, 
  "also": 6, 
  "football": 7, 
  "games": 8, 
  "Mary": 9, 
  "too": 10
}

該字典中包含10個單詞, 每一個單詞有惟一索引,注意它們的順序和出如今句子中的順序沒有關聯. 根據這個字典, 咱們能將上述兩句話從新表達爲下述兩個向量:

[1, 2, 1, 1, 1, 0, 0, 0, 1, 1]
[1, 1, 1, 1, 0, 1, 1, 1, 0, 0]

這兩個向量共包含10個元素, 其中第i個元素表示字典中第i個單詞在句子中出現的次數. 所以BoW模型可認爲是一種統計直方圖 (histogram). 在文本檢索和處理應用中, 能夠經過該模型很方便的計算詞頻.

可是從上面咱們也可以看出,在構造文檔向量的過程當中能夠看到,咱們並無表達單詞在原來句子中出現的次序這也是bag of words的一個缺點,可是聽師兄說,不少狀況簡單的用bow特徵產生的結果就比較好了

根據上面介紹到的詞袋模型,咱們能夠把一個文檔轉換成一個向量,向量的長度是詞典的大小,也就是文檔集裏詞項的數量,而向量中的每一個元素都是都是對應詞項的詞頻。同理,用戶的查詢也能轉換爲一個向量,好比在上述的情境下,若是用戶查詢是「football games」,那麼對應的向量就是[0,0,0,0,0,0,1,1,0,0] 。如今,咱們就可使用線性代數的方法來求得兩個向量的類似度,從而獲得用戶查詢和全部文檔對應的類似度。典型的方法就是求得條用戶查詢向量與文檔向量之間的餘弦夾角,夾角越小,類似度越大。具體的求法以下:

假定A和B是兩個n維向量,A是 [A1, A2, ..., An] ,B是 [B1, B2, ..., Bn] ,則A與B的夾角θ的餘弦等於:

cos-similarity

這種方法雖然用到了形式化數學的方法,可是本質上的思想很簡單:包含用戶查詢中關鍵詞的文檔才與用戶的查詢相關。一篇文檔包含的關鍵詞越多,關鍵詞出現的頻率越高,這篇文檔與用戶查詢的相關度就越高

可是如今問題又來了,有一些詞好比「a」,「the」, 「of」,或者「啊」, 「的」, 「了」,它們基本上在每一篇文檔都出現,並且在每一篇文檔中的出現頻率都很高,用戶查詢中也驚顫會包含這些詞。

顯然這些詞是沒什麼價值的,不能幫咱們找出真正與用戶查詢相關的文檔的。那咱們要怎麼作來消除這些詞的影響呢?

一個簡單粗暴的方法是維護一個停用詞表,也就是把一些沒有價值的詞,也就是在絕大多數文檔都出現的詞記錄成一張表,在建索引和解析用戶查詢時忽略這些詞。

一個更有技術含量的方法是,在向量化文檔和用戶查詢時,給每一個詞賦予權重,使得重要的詞權重高,「a」,「啊」之類的詞權重低。那麼文檔向量和用戶查詢向量裏的元素就再也不是詞頻這樣簡單的指標,而是詞在文檔中的權重這樣的指標。這種權重指標中最經常使用的方法就是TF-IDF。其核心思想是,在絕大多數文檔的中都出現的詞重要性最低,只在少數文檔中出現的詞重要性較高,這些詞的詞頻越高,重要性越高。所以,IF-iDF的計算方法以下:

一些符號: t--某個詞項, d--某篇文檔, n--文檔集包含的文檔總數

第一步,計算詞頻。**

tf = 詞項t在文章d中的出現次數 / 文章d的總詞項數

第二步,計算逆文檔頻率。

idf = lg(文檔集規模n / 包含詞項t的文檔數 + 1)

第三步,計算TF-IDF。

tf-idf = tf * idf

Again, talk is cheap。下面是一段簡單的python代碼,演示使用VSM來計算用戶查詢和文檔類似度。

"""
vsm.py

Simple implementation of Vector Space Model

Note: Depend on Numpy, please install it ahead (`pip install numpy`)

Please Run this script using Python3.x 
Tested under Python3.6, Win7 and Python3.5 ubuntu16.04
Author: Richy Zhu
Email: rickyzhu@foxmail.com
"""

from math import log10
from pprint import pprint
import numpy as np

def _tf(tokenized_doc):
    """calculate term frequency for each term in each document"""
    term_tf = {}
    for term in tokenized_doc:
        if term not in term_tf:
            term_tf[term]=1.0
        else:
            term_tf[term]+=1.0

    # pprint(term_tf)
    return term_tf

def _idf(indices, docs_num):
    """calculate inverse document frequency for every term"""
    term_df = {}
    for term in indices:
        # 一個term的df就是倒排索引中這個term的倒排記錄表(對應文檔列表)的長度 
        term_df.setdefault(term, len(indices[term]))
    
    term_idf = term_df
    for term in term_df:
        term_idf[term] = log10(docs_num /term_df[term])
    # pprint(term_idf)
    return term_idf

def tfidf(tokenized_docs, indices):
    """calcalate tfidf for each term in each document"""
    term_idf = _idf(indices, len(tokenized_docs))
        
    term_tfidf={}
    doc_id=0
    for tokenized_doc in tokenized_docs:
        term_tfidf[doc_id] = {}
        term_tf = _tf(tokenized_doc)
        
        doc_len=len(tokenized_doc)
        for term in tokenized_doc:
            tfidf = term_tf[term]/doc_len * term_idf[term]
            term_tfidf[doc_id][term] =tfidf
        doc_id+=1
    # pprint(term_tfidf)
    return term_tfidf

def build_terms_dictionary(tokenized_docs):
    """assign an ID for each term in the vocabulary"""
    vocabulary = set()
    for doc in tokenized_docs:
        for term in doc:
            vocabulary.add(term)
    vocabulary = list(vocabulary)
    dictionary = {}
    for i in range(len(vocabulary)):
        dictionary.setdefault(i, vocabulary[i])
    return dictionary

def vectorize_docs(docs_dict, terms_dict, tf_idf):
    """ transform documents to vectors
        using bag-of-words model and if-idf
    """
    docs_vectors = np.zeros([len(docs_dict), len(terms_dict)])

    for doc_id in docs_dict:
        for term_id in terms_dict:
            if terms_dict[term_id] in tf_idf[doc_id]:
                docs_vectors[doc_id][term_id] = tf_idf[doc_id][terms_dict[term_id]]
    return docs_vectors

def vectorize_query(tokenized_query, terms_dict):
    """ transform user query to vectors 
        using bag-of-words model and vector normalization
    """
    query_vector = np.zeros(len(terms_dict))
    for term_id in terms_dict:
        if terms_dict[term_id] in tokenized_query:
            query_vector[term_id] += 1
    return query_vector / np.linalg.norm(query_vector)

def cos_similarity(vector1, vector2):
    """compute cosine similarity of two vectors"""
    return np.dot(vector1,vector2)/(np.linalg.norm(vector1)*(np.linalg.norm(vector2))) 

def compute_simmilarity(docs_vectors, query_vector, docs_dict):
    """compute all similarites between user query and all documents"""
    similarities = {}
    for doc_id in docs_dict:
        similarities[doc_id] = cos_similarity(docs_vectors[doc_id], query_vector)
    return similarities


if __name__ == '__main__':
    tokenized_docs = [
        ['hello', 'world'],
        ['hello', 'python'],
        ['i', 'love', 'c', 'java', 'python', 'typescript', 'and', 'php'],
        ['use', 'python', 'to', 'build', 'inverted', 'indices'],
        ['you', 'and', 'me', 'are', 'in', 'one', 'world']
                    ]
    tokenized_query = ["python", "indices"]
    docs_dict = {
        0: "docs[0]",
        1: "docs[1]",
        2: "docs[2]",
        3: "docs[3]",
        4: "docs[4]"
    }
    indices = {'and': [2, 4], 'are': [4], 'build': [3], 'c': [2], 'hello': [0, 1], 'i': [2], 
            'in': [4], 'indices': [3], 'inverted': [3], 'java': [2], 'love': [2], 'me': [4],
            'one': [4], 'php': [2], 'python': [1, 2, 3], 'to': [3], 'typescript': [2], 'use'
            : [3], 'world': [0, 4], 'you': [4]}
    tf_idf = tfidf(tokenized_docs, indices)
    terms_dict = build_terms_dictionary(tokenized_docs);
    docs_vectors = vectorize_docs(docs_dict, terms_dict, tf_idf)
    query_vector = vectorize_query(tokenized_query, terms_dict)
    # pprint(docs_vectors)
    pprint(compute_simmilarity(docs_vectors, query_vector, docs_dict))

運行以上腳本能夠獲得下面的結果,字典作點是文檔id,右邊是對應的用戶查詢的類似度。可見文檔3與用戶查詢最爲相關。

$ python3 vsm.py
{0: 0.0,
 1: 0.34431538823149532,
 2: 0.088542411007409116,
 3: 0.41246212572975449,
 4: 0.0}

關於向量空間模型的資料,有不少更加詳細,更加通俗易懂的文章,好比吳軍博士《數學之美》的第11章: 肯定網頁和查詢的相關性:TF-IDF,Manning等人《信息檢索導論》的第6章: Scoring, term weighting, and the vector space model

小結

因此向量空間模型的要點是把文檔轉換成向量,把用戶的查詢也轉換成向量,而後求查詢向量和全部文檔向量的餘弦夾角等類似度指標,根據類似度來排序。

可是對大規模文檔集,不可能把用戶查詢跟全部文檔向量的類似度都計算一遍,這樣太耗費時間了。咱們能夠犧牲一點點搜索質量,來獲取時間性能上的大幅提升。首先咱們能夠結合倒排索引,先根據用戶查詢的所有或部分關鍵詞,在索引中找出相關文檔列表,而後只對搜索出來的文檔進行類似度計算。若是這一步後找出來的文檔依然太多,咱們能夠更進一步,先根據每一個詞在每一篇文檔中TF-IDF值對文檔進行排序,排序高的放在這個詞對應的文檔列表前面。這樣,咱們能夠每次只選出關鍵詞對應的文檔列表的前K個文檔作類似度計算,便徹底能夠控制時間成本和搜索質量之間的平衡了。

至此,一個基於倒排索引和向量空間模型的全文搜索引擎的核心工做機制就完備了。

信息檢索當下的應用和將來可能的發展方向有哪些?

答曰:

前文詳細介紹了一種主要使用倒排索引和向量空間模型的信息檢索方案,主要用於檢索計算機裏的文檔。早期的Google等互聯網搜索引擎主要採用的都是這種方案。甚至如今,這種方案可能也仍是Google的主要框架。這種搜索引擎也稱爲「ad hoc search engine」, 「ad hoc」在拉丁文中是「特殊的、臨時的、針對特定目的」的意思。也就是說咱們經常使用的搜索引擎針對獲得用戶信息需求都是「特殊的、臨時的、針對特定目的」。相應的,也有長期的,穩定的信息需求,好比一個長期關注信息檢索技術的人,就想要天天閱讀一些信息檢索主題的文章。更加常見的長期、穩定的信息需求,多是「在一大堆郵件中找出垃圾郵件(而後丟掉)」。針對這些信息需求,咱們須要文檔集進行分類等操做,找出文檔集裏「信息檢索技術」主題的文章,或者對郵件集操做,找出「垃圾郵件」類別的郵件(而後丟掉)。典型的方案就是貝葉斯文本分類、支持向量機文本分類,K臨近文本聚類之類額機器學習習方法。Manning等人的《信息檢索導論》後面好幾章都是介紹這些機器學習方法在文本分類和聚類中的應用。

當下,搜索引擎是信息檢索的主要工具和研究分支。可是讓咱們從新檢視信息檢索的定義:

Information retrieval (IR) is finding material (usually documents) of an unstructured nature (usually text) that satisfies an information need from within large collections (usually stored on computers).

信息檢索的本質,應該是「給用戶找到他想要的信息」。那麼若是用戶提出一個問題,而後咱們不是返回一堆文檔,而是直接告訴他問題的答案,豈不是更好?是的,人們把自動問答系統看做是下一代的搜索引擎,而Google、百度、搜狗等人工智能和信息檢索巨頭也正在大力開發自動問答系統。

讓咱們更激進一點,若是信息檢索的本質是「給用戶找到他想要的信息」,那麼更加高端的信息檢索形式多是在用戶提出問題以前就給他提供他想要的信息,好比用戶剛想換一部手機,就把全部手機相關的商品信息呈現給用戶;或者說用戶剛想了解一下娛樂圈某明星最近發生的一件事,系統就他推送相關新聞給這位用戶。是的,推薦系統可能纔是信息檢索最高級的形態,這可能也是不少人看好今日頭條的緣故吧。


相關連接:

一些參考代碼:https://coding.net/u/qige96/p/IR-exe

本文直接或簡介地使用瞭如下著做的內容:

  1. 《信息檢索導論》
  2. 知乎文章:bag-of-words模型入門
  3. 阮一峯:TF-IDF與餘弦類似性的應用(一):自動提取關鍵詞
  4. 阮一峯:TF-IDF與餘弦類似性的應用(二):找出類似文章
  5. 吳軍:《數學之美》

本做品首發於簡書平臺,採用知識共享署名 4.0 國際許可協議進行許可。

相關文章
相關標籤/搜索