官术网_书友最值得收藏!

3.3.7 跨度查詢

若查詢詞是“吃飯”,而文檔中出現了“吃完飯”這樣的詞。把查詢詞和文檔都按最小粒度分詞,分成“吃”和“飯”兩個詞。文檔中的這兩個詞雖然不是連續出現,但只間隔了一個詞。

近似查詢假設同時查詢的幾個詞之間的匹配點很近,則這樣的文檔可能也是要查找的。匹配詞在文檔中的位置信息用跨度(Spans)描述。抽象類Spans封裝了一次匹配的文檔和位置信息。span是一個<文檔編號,開始位置,結束位置>的三元組。

Spans的接口定義如下:

        boolean next() //移動到下一個匹配的文檔
        boolean skipTo(int target)//跳到指定的文檔
        int doc()//當前的文檔編號
        int start()//匹配區域的開始位置
        int end() //匹配區域的結束位置

TermSpans是Spans的具體子類。

SpanQuery稱為跨度查詢,用于查詢多個詞時考慮幾個詞在文檔中的匹配位置。SpanQuery和PhraseQuerys或者MultiPhraseQuerys很相似,因為都是通過位置限制匹配,但是SpanQuery更靈活。

SpanNearQuery用來查詢在比較近的區域內出現的多個查詢詞。例如,下面這個查詢既可以匹配“吃飯”,又可以匹配“吃完飯”。

        new SpanNearQuery(new SpanQuery[] {
          new SpanTermQuery(new Term(FIELD, "吃")), //第1個詞
          new SpanTermQuery(new Term(FIELD, "飯"))},  //第2個詞
          1, //在1個位置以內
          true); //有序

SpanTermQuery是一個最基礎的跨度搜索實現類,因為可以通過它得到一個詞的位置信息。在SpanNearQuery的構造方法中可以指定一些查詢詞需要在多近的區域出現。

同樣的幾個詞在一起,但是如果順序不一樣,意思可能就不一樣。例如,“花的中間”與“中間的花”意義就不一樣,類似的例子還有“媽媽愛自己的兒女”和“兒女愛自己的媽媽”。所以,SpanNearQuery有一個參數表示是否要求按數組中的順序匹配。

例如,需要查找lucene和doug在5個位置以內,doug在lucene之后,也就是說,詞出現的順序是需要考慮的。可以使用如圖3-11所示的SpanNearQuery。

圖3-11 SpanNearQuery

        SpanQuery[] baseQueries = new SpanQuery[] {
                        new SpanTermQuery(new Term(FIELD, "lucene")),
                        new SpanTermQuery(new Term(FIELD, "doug"))};
        //這里的true表示詞必須按數組中的順序出現在文檔中
        new SpanNearQuery(baseQueries, 5, true);

在這個例子中,lucene和doug的間隔在3以內,也就是間隔了3個詞。

SpanNearQuery會查找互相在給定距離內的一些數量的SpanQuery。可以指定span是按順序或者不按順序查詢。SpanNearQuery根據SpanQuery對象組成的數組來構建。因為SpanTermQuery是SpanQuery的子類,所以可以根據SpanTermQuery構造出SpanNearQuery。

SpanNearQuery構造方法接收一個SpanQuery數組。span之間的距離,一個布爾值表明是否要求按SpanQuery數組中的順序出現。下面是另一個嵌套的例子。這次,查找doug在lucene之后的5個間隔內,而hadoop在lucene → doug之后的4個間隔內,如圖3-12所示。

圖3-12 嵌套的SpanNearQuery

        SpanNearQuery spanNear = new SpanNearQuery(new SpanQuery[] {
            new SpanTermQuery(new Term(FIELD, "lucene")),
            new SpanTermQuery(new Term(FIELD, "doug"))},
            5,
            true);


        new SpanNearQuery(new SpanQuery[] {
            spanNear,
            new SpanTermQuery(new Term(FIELD, "hadoop"))},
            4,
            true);

有些列,例如標題,頭幾個詞可能更重要,可以使用SpanFirstQuery限定只查詢前幾個詞。例如,查找名稱以“玩具”開頭的產品。

        SpanTermQuery toy = new SpanTermQuery(new Term("title", "玩具"));
        SpanFirstQuery first = new SpanFirstQuery(toy, 1); //限定在頭一個位置出現

可以把SpanFirstQuery看成是SpanNearQuery的特例,第一個詞是一個虛擬的開始詞,從第二個詞開始才是真正的匹配詞。

例如,有兩個文檔“I love Lucene”和“Lucene is nice”,想要能夠查詢Lucene出現在最開始的文檔,也就是匹配正則表達式“^Lucene .*”的文檔。

        SpanTermQuery lucene = new SpanTermQuery(new Term("title", "Lucene"));
        SpanFirstQuery first = new SpanFirstQuery(lucene, 1); //限定在頭一個位置出現

SpanRegexQuery使用標準的正則表達式語法。例如,查詢年:2000, 2001, 2002, ..., 2009。

        SpanRegexQuery srq = new SpanRegexQuery(new Term("year", "200.? "));

SpanNotQuery包含必須滿足的SpanQuery和必須排除的SpanQuery。例如,要查找Microsoft Windows,但是不匹配Microsoft Windows之后的文檔是大寫的,偽代碼如下:

        SpanNot:
            include:
              SpanNear(in-order=true, slop=0):
                  SpanTerm: "Microsoft"
                  SpanTerm: "Windows"
            exclude:
              SpanNear(in-order=true, slop=0):
                  SpanTerm: "Microsoft"
                  SpanTerm: "Windows"
                  SpanRegex: "^\\p{Lu}.*"

實際的代碼:

        SpanNearQuery includeQuery = new SpanNearQuery(new SpanQuery[] {
          new SpanTermQuery(new Term(FIELD, "Microsoft")),
          new SpanTermQuery(new Term(FIELD, "Windows"))},
          0,
          true);


        SpanRegexQuery upperCaseQuery = new SpanRegexQuery( new Term(FIELD,
        "^\\p{Lu}.*"));
        SpanNearQuery excludeQuery = new SpanNearQuery(new SpanQuery[] {
          new SpanTermQuery(new Term(FIELD, "Microsoft")),
          new SpanTermQuery(new Term(FIELD, "Windows")),
          upperCaseQuery },
          0,
          true);

若想查找包含“喜歡”一詞,并且在其前面沒有“不”字的文檔。可以這樣:

        SpanNotQuery(like, SpanNearQuery(not, like))

再擴展出同類查詢詞,也就是:

        SpanNotQuery(
              SpanOrQuery(喜歡,愛...)
              SpanNearQuery(
                    SpanOrQuery(不)
                    SpanOrQuery(喜歡,愛...)
                    )
              )

SpanOrQuery可以匹配符合任何一個條件的文檔。

        SpanTermQuery term1 = new SpanTermQuery(new Term("field", "thirty"));
        SpanTermQuery term2 = new SpanTermQuery(new Term("field", "three"));
        SpanNearQuery near1 = new SpanNearQuery(new SpanQuery[] {term1, term2},
                                          0, true);
        SpanTermQuery term3 = new SpanTermQuery(new Term("field", "forty"));
        SpanTermQuery term4 = new SpanTermQuery(new Term("field", "seven"));
        SpanNearQuery near2 = new SpanNearQuery(new SpanQuery[] {term3, term4},
                                          0, true);


        SpanOrQuery query = new SpanOrQuery(new SpanQuery[] {near1, near2});

例如,說一個人壞透了,用“頭上長瘡,腳下流膿”來形容。這個條件可以這樣描述:

        SpanAndQuery(
              SpanFirstQuery(瘡)
              SpanLastQuery(膿)
        )

SpanAndQuery和SpanLastQuery都還沒有現成的實現例子。

主站蜘蛛池模板: 武强县| 郯城县| 营口市| 渑池县| 哈巴河县| 凌云县| 万源市| 娄烦县| 密山市| 扎兰屯市| 盐城市| 石阡县| 五寨县| 凉山| 龙川县| 英超| 进贤县| 大新县| 崇文区| 台山市| 漯河市| 云南省| 荃湾区| 张家口市| 贵溪市| 连州市| 平邑县| 汉川市| 安平县| 新建县| 简阳市| 闽清县| 保定市| 赤峰市| 陇川县| 社旗县| 浏阳市| 合川市| 洛南县| 乌鲁木齐县| 栾城县|