搜索學(xué)習(xí)基礎(chǔ)--代碼模擬倒排索引過程

之前已經(jīng)分析了倒排索引的過程倒排索引過程解讀 那么噪裕,接下來用代碼實現(xiàn)一下其過程股毫,加深了解:

package search;


import java.util.*;

/**
 * 模擬倒排索引(只支持英文)
 *
 * @author yuyufeng
 * @date 2017/10/31
 */
public class InvertedIndex {

    /**
     * 倒排索引表
     */
    Map<String, IndexTable> keywordsIndexTableMap = new HashMap<>();

    /**
     * 停頓詞
     */
    Set<String> stopwords = new HashSet<>();

    /**
     * 存儲文檔
     */
    List<String> store;

    public InvertedIndex(List<String> list) {
        store = list;
        for (int i = 0; i < list.size(); i++) {
            String li = keywordsHandler(list.get(i));
            String[] array = li.split(" ");
            for (int j = 0; j < array.length; j++) {
                addKeyWords(array[j], i, j);
            }
        }
        //停頓詞 非關(guān)鍵詞
        stopwords.add("is");
        stopwords.add("and");
        stopwords.add("or");
        stopwords.add("the");
    }

    /**
     * 建立索引 建立倒排索引表
     */
    public void addKeyWords(String keywords, Integer i, Integer j) {
        //去空
        if ("".equals(keywords)) {
            return;
        }
        IndexTable indexTable = keywordsIndexTableMap.get(keywords);
        if (indexTable == null) {
            //插入關(guān)鍵詞信息
            indexTable = new IndexTable();
            indexTable.keywords = keywords;
            //插入關(guān)鍵詞出現(xiàn)的文檔Id,次數(shù)為1(首次出現(xiàn))
            indexTable.docTimes.put(i, 1);
            //插入關(guān)鍵詞出現(xiàn)的文檔Id,在文檔中位置
            indexTable.docIndex.put(i, " "+j);
            keywordsIndexTableMap.put(keywords, indexTable);
        } else {
            //更新關(guān)鍵詞出現(xiàn)的文檔祭陷、頻率
            indexTable.docTimes.put(i, indexTable.docTimes.get(i) == null ? 1 : indexTable.docTimes.get(i) + 1);
            //更新關(guān)鍵詞出現(xiàn)的文檔趣席、位置
            indexTable.docIndex.put(i, (indexTable.docIndex.get(i) == null ? "" : indexTable.docIndex.get(i)) + " " + j);
            keywordsIndexTableMap.put(keywords, indexTable);
        }
    }


    //去除無關(guān)詞,統(tǒng)一大小寫
    private String keywordsHandler(String doc) {
        doc = doc.replaceAll(",|:|\\.", " ");
        doc = doc.toLowerCase();
        return doc;
    }

    /**
     * 查詢
     * @param keywords
     * @return
     */
    public List<String> search(String keywords) {
        keywords = keywordsHandler(keywords);

        //用Set可以去重
        String[] kewordsArray = keywords.split(" ");

        List<String> result = new ArrayList<>();

        //<文檔想罕,出現(xiàn)次數(shù)>
        Map<Integer, DocTemp> docSortTimes = new HashMap();

        for (int i = 0; i < kewordsArray.length; i++) {
            String key = kewordsArray[i];
            IndexTable indexTable = keywordsIndexTableMap.get(key);
            if (indexTable == null) {
                continue;
            }
            //找到關(guān)鍵詞霉涨,統(tǒng)計出現(xiàn)的文檔笙瑟,頻率,出現(xiàn)的文檔數(shù)
            for (Integer integer : indexTable.docTimes.keySet()) {
                if (docSortTimes.get(integer) == null) {
                    DocTemp docTemp = new DocTemp();
                    docTemp.docId = integer;
                    docTemp.times = 1;
                    docTemp.allTimes = indexTable.docTimes.get(integer);
                    docSortTimes.put(integer, docTemp);
                } else {
                    DocTemp docTemp = docSortTimes.get(integer);
                    docTemp.times++;
                    docTemp.allTimes += indexTable.docTimes.get(integer);
                }
            }
        }

        List<DocTemp> docTemps = new ArrayList<>();
        //轉(zhuǎn)化List 排序
        for (Integer docId : docSortTimes.keySet()) {
            DocTemp docTemp = docSortTimes.get(docId);
            docTemps.add(docTemp);
        }

        //對結(jié)果排序鸠蚪,一個Doc包含關(guān)鍵詞越多师溅,排名越前。如相等蘸鲸,則比較出現(xiàn)總次數(shù)  \\這個規(guī)則可以自定義
        docTemps.sort(new Comparator<DocTemp>() {
            @Override
            public int compare(DocTemp o1, DocTemp o2) {
                if(o1.times.equals(o2.times)){
                    return o2.allTimes - o1.times;
                }
                return o2.times-o1.times;
            }
        });

        //包裝結(jié)果
        for (int i = 0; i < docTemps.size(); i++) {
            result.add(store.get(docTemps.get(i).docId));
        }

        return result;
    }

    public static void main(String[] args) {
        List<String> docs = new ArrayList<>();
        //docId = 0
        String doc = "Inverted index comes from the actual application, it needs to find the record according to the value of the attribute.";
        docs.add(doc);
        //docId = 1
        doc = "Each item Each in the index table includes an attribute value and the address of each record with the attribute value";
        docs.add(doc);
        //docId = 2
        doc = "Attribute values are not determined by records";
        docs.add(doc);
        //docId = 3
        doc = "Rather, the location of the record is determined by the attribute value";
        docs.add(doc);
        //docId = 4
        doc = "It is called inverted index";
        docs.add(doc);
        //docId = 5
        doc = "The data operation is simple: the data used by the search engine is easy to operate, generally speaking, only need to add, delete, change, check several functions";
        docs.add(doc);
        //docId = 6
        doc = "And data has a specific format, you can design simple and efficient applications for these applications";
        docs.add(doc);
        //建立索引
        InvertedIndex invertedIndex = new InvertedIndex(docs);

        //查看倒排索引表
        System.out.println("關(guān)鍵詞 出現(xiàn)doc[次數(shù)],{位置}");
        for (String key : invertedIndex.keywordsIndexTableMap.keySet()) {
            System.out.print(key + " ");
            IndexTable indexTable = invertedIndex.keywordsIndexTableMap.get(key);
            for (Integer integer : indexTable.docTimes.keySet()) {
                System.out.print(integer + "[" + indexTable.docTimes.get(integer) + "],");
                System.out.print("{" + indexTable.docIndex.get(integer) + "} ");
            }
            System.out.println("");
        }


        //執(zhí)行查詢
        List<String> results = invertedIndex.search("specific format location determined attribute");

        System.out.println("=========== 查詢結(jié)果 ==========");
        for (String result : results) {
            System.out.println(result);
        }
    }
}

/**
 * 倒排索引表
 */
class IndexTable {
    /**
     * 關(guān)鍵詞
     */
    String keywords;

    /**
     * 出現(xiàn)頻率
     */
    Map<Integer, Integer> docTimes = new HashMap<>();

    /**
     * 出現(xiàn)位置
     */
    Map<Integer, String> docIndex = new HashMap<>();
}

/**
 * 用于排序
 */
class DocTemp {
    Integer docId;
    Integer times;  //出現(xiàn)在多少Doc中
    Integer allTimes;  //出現(xiàn)總次數(shù)
}

運行結(jié)果

關(guān)鍵詞 出現(xiàn)doc[次數(shù)],{位置}
called 4[1],{ 2} 
data 5[2],{ 1 7} 6[1],{ 1} 
functions 5[1],{ 32} 
several 5[1],{ 31} 
simple 5[1],{ 4} 6[1],{ 10} 
used 5[1],{ 8} 
these 6[1],{ 15} 
speaking 5[1],{ 19} 
find 0[1],{ 11} 
record 0[1],{ 13} 1[1],{ 16} 3[1],{ 6} 
only 5[1],{ 21} 
from 0[1],{ 3} 
has 6[1],{ 2} 
inverted 0[1],{ 0} 4[1],{ 3} 
you 6[1],{ 7} 
needs 0[1],{ 9} 
add 5[1],{ 24} 
actual 0[1],{ 5} 
item 1[1],{ 1} 
in 1[1],{ 3} 
need 5[1],{ 22} 
format 6[1],{ 5} 
index 0[1],{ 1} 1[1],{ 5} 4[1],{ 4} 
includes 1[1],{ 7} 
is 3[1],{ 7} 4[1],{ 1} 5[2],{ 3 13} 
it 0[1],{ 8} 4[1],{ 0} 
check 5[1],{ 30} 
an 1[1],{ 8} 
easy 5[1],{ 14} 
each 1[3],{ 0 2 15} 
operate 5[1],{ 16} 
determined 2[1],{ 4} 3[1],{ 8} 
records 2[1],{ 6} 
rather 3[1],{ 0} 
values 2[1],{ 1} 
comes 0[1],{ 2} 
according 0[1],{ 14} 
for 6[1],{ 14} 
delete 5[1],{ 26} 
can 6[1],{ 8} 
not 2[1],{ 3} 
search 5[1],{ 11} 
are 2[1],{ 2} 
engine 5[1],{ 12} 
and 1[1],{ 11} 6[2],{ 0 11} 
of 0[1],{ 18} 1[1],{ 14} 3[1],{ 4} 
by 2[1],{ 5} 3[1],{ 9} 5[1],{ 9} 
design 6[1],{ 9} 
attribute 0[1],{ 20} 1[2],{ 9 19} 2[1],{ 0} 3[1],{ 11} 
value 0[1],{ 17} 1[2],{ 10 20} 3[1],{ 12} 
table 1[1],{ 6} 
a 6[1],{ 3} 
address 1[1],{ 13} 
efficient 6[1],{ 12} 
change 5[1],{ 28} 
specific 6[1],{ 4} 
generally 5[1],{ 18} 
the 0[4],{ 4 12 16 19} 1[3],{ 4 12 18} 3[3],{ 2 5 10} 5[3],{ 0 6 10} 
with 1[1],{ 17} 
application 0[1],{ 6} 
location 3[1],{ 3} 
to 0[2],{ 10 15} 5[2],{ 15 23} 
operation 5[1],{ 2} 
applications 6[2],{ 13 16} 
=========== 查詢結(jié)果 ==========
Inverted index comes from the actual application, it needs to find the record according to the value of the attribute.
It is called inverted index
Each item Each in the index table includes an attribute value and the address of each record with the attribute value
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末窑多,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子技潘,更是在濱河造成了極大的恐慌千康,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件值桩,死亡現(xiàn)場離奇詭異豪椿,居然都是意外死亡,警方通過查閱死者的電腦和手機砂碉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門增蹭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來磅摹,“玉大人,你說我怎么就攤上這事饼灿〉勖溃” “怎么了?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵庇忌,是天一觀的道長舰褪。 經(jīng)常有香客問我,道長略就,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任窄绒,我火速辦了婚禮崔兴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恼布。我一直安慰自己,他們只是感情好倔幼,可當(dāng)我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布损同。 她就那樣靜靜地躺著鸟款,像睡著了一般。 火紅的嫁衣襯著肌膚如雪何什。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天伶贰,我揣著相機與錄音罐栈,去河邊找鬼。 笑死琅翻,一個胖子當(dāng)著我的面吹牛柑贞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辩尊,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼康辑,長吁一口氣:“原來是場噩夢啊……” “哼轿亮!你這毒婦竟也來了胸墙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤但骨,失蹤者是張志新(化名)和其女友劉穎智袭,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體校哎,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡闷哆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年单起,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屈留。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡括儒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情赠摇,我是刑警寧澤,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布烫罩,位于F島的核電站洽故,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏隘弊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一开镣、第九天 我趴在偏房一處隱蔽的房頂上張望咽扇。 院中可真熱鬧,春花似錦树埠、人聲如沸嘶伟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耽装。三九已至,卻和暖如春掉奄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背诞仓。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工速兔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谍婉。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓镀钓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親唤蔗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 第七章 黑白村 當(dāng)安妮醒來時箱季,她發(fā)現(xiàn)亨德爾已經(jīng)可以站起來领虹,并走路了∷呱裕科爾托見安妮醒了,說道...
    27315涵閱讀 382評論 0 1
  • 小時候,白雪公主與七個小矮人努酸、勇敢的錫兵這些童話故事陪伴了我的童年,也比較喜歡看書仍源,回頭想想舔涎,那段時光是非...
    金塔094羅瑞閱讀 285評論 0 6
  • 慢長的冬夜有些清冷,看著沉睡的雪花不免羨慕嚎于!就那么輕盈優(yōu)美挟冠,滿懷喜悅的投入大地的懷抱于购,安心知染,踏實,擁有可靠的懷抱色瘩。
    溪間月閱讀 189評論 0 0