Elasticsearch系列(8)Search之折疊牙咏、過濾及高亮

1. 折疊

使用collapse參數(shù)根據(jù)字段折疊搜索結(jié)果臼隔。折疊會合并指定折疊字段內(nèi)容相同的數(shù)據(jù),并選擇排序文檔結(jié)果集中第一個文檔返回妄壶。例如摔握,按照user.id折疊搜索結(jié)果,示例如下:

PUT my_index_01
{
  "mappings": {
    "properties": {
      "message": {
        "type": "text"
      },
      "user.id": {
        "type": "long"
      },
      "user.name": {
        "type": "keyword"
      },
      "http.response.bytes": {
        "type": "integer"
      },
      "@timestamp": {
        "type": "date"
      }
    }
  }
}
PUT my_index_01/_doc/1
{
  "message": "GET /search",
  "user": {
    "id": 10001,
    "name": "johnny"
  },
  "@timestamp": "2015-01-01",
  "http.response.bytes": 10
}
PUT my_index_01/_doc/2
{
  "message": "GET /_doc",
  "user": {
    "id": 10001,
    "name": "johnny"
  },
  "@timestamp": "2015-01-02",
  "http.response.bytes": 8
}
GET /my_index_01/_search
{
  "query": {
    "match": {
      "message": "GET /search"
    }
  },
  "collapse": {
    "field": "user.id"                
  }
}

返回折疊結(jié)果

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      {
        "_index" : "my_index_01",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.8754687,
        "_source" : {
          "message" : "GET /search",
          "user" : {
            "id" : 10001,
            "name" : "johnny"
          }
        },
        "fields" : {
          "user.id" : [
            10001
          ]
        }
      }
    ]
  }
}
  • collapse.field參數(shù)使用的必須是數(shù)字類型或keyword類型的單個值字段丁寄,并且字段的doc_values激活氨淌。

擴展折疊結(jié)果

對于每個折疊后的命中結(jié)果集,可以再次請求其多個inner_hits伊磺,在展示折疊命中結(jié)果集多種表示形式時有用盛正,通過參數(shù)collapse. inner_hits可以做到,示例如下:

GET /my_index_01/_search
{
  "query": {
    "match": {
      "message": "GET /search"
    }
  },
  "collapse": {
    "field": "user.id",                      
    "inner_hits": [
      {
        "name": "largest_responses",         //1
        "size": 1,
        "sort": [ {"http.response.bytes":"desc"} ]
      },
      {
        "name": "most_recent",             //2  
        "size": 1,
        "sort": [ { "@timestamp": "asc" } ]
      }
    ]
  },
  "sort": [ "http.response.bytes" ]
}

注釋1:inner_hits結(jié)果集名稱為largest_responses奢浑,基于折疊后搜索結(jié)果蛮艰,按照http.response.bytes倒敘排列,并獲取size指定條數(shù)的數(shù)據(jù)雀彼。
注釋2:inner_hits結(jié)果集名稱為most_recent壤蚜,基于折疊后搜索結(jié)果,按照@timestamp順序排列徊哑,并獲取size指定條數(shù)的數(shù)據(jù)袜刷。

二級折疊

inner_hits也支持再次折疊,通過參數(shù)collapse. inner_hits. collapse可以折疊inner_hits結(jié)果集莺丑。示例如下:

GET /my_index_01/_search
{
  "query": {
    "match": {
      "message": "GET /search"
    }
  },
  "collapse": {
    "field": "user.id",                      
    "inner_hits": [
      {
        "name": "largest_responses",         
        "size": 2,
        "collapse": { "field": "user.name" },
        "sort": [ {"http.response.bytes":"desc"} ]
      }
    ]
  }
}

2. 過濾

可以使用以下兩種方式來過濾搜索結(jié)果:

(1)使用帶有filter子句的boolean query(布爾查詢)著蟹。搜索請求中的搜索命中集和聚合都可使用boolean filters(boolean過濾器),即聚合會基于boolean query過濾梢莽。
(2)使用search API(搜索API)中的post_filter參數(shù)萧豆。搜索請求僅將post過濾器應(yīng)用于搜索命中集,不會應(yīng)用于聚合昏名′汤祝可以使用post過濾器基于更廣泛的結(jié)果集來進行計算聚合,然后進一步縮小結(jié)果轻局。

可以在post過濾器之后重新計算得分洪鸭,以提高相關(guān)性和結(jié)果重排。

Post過濾器

使用post_filter參數(shù)來過濾搜索結(jié)果仑扑,但它不影響聚合結(jié)果览爵。例如,搜索華為品牌镇饮,紅色類型的手機蜓竹,并且希望聚合所有華為手機,操作示例如下:

PUT /my_index_phone
{
  "mappings": {
    "properties": {
      "brand": { "type": "keyword" },
      "color": { "type": "keyword" },
      "model": { "type": "keyword" }
    }
  }
}
PUT /my_index_phone/_doc/1?refresh
{"brand":"huawei","color":"red","model":"mate40"}
PUT /my_index_phone/_doc/2?refresh
{"brand":"huawei","color":"red","model":"p30"}
PUT /my_index_phone/_doc/3?refresh
{"brand":"huawei","color":"white","model":"p30"}

GET /my_index_phone/_search
{
  "query": {
    "bool": {
      "filter": { //1
        "term": { "brand": "huawei" }  
      }
    }
  },
  "aggs": {
    "colors": { //2
      "terms": { "field": "color" } 
    },
    "color_red": { //3
      "filter": {
        "term": { "color": "red" } 
      },
      "aggs": {
        "models": {
          "terms": { "field": "model" } 
        }
      }
    }
  },
  "post_filter": {  //4
    "term": { "color": "red" }
  }
}

注釋1:boolean查詢過濾 品牌為華為的手機,此查詢影響聚合操作梅肤,會影響操作2和3司蔬。
注釋2:以color字段聚合,也就是按顏色歸類聚合華為手機姨蝴,有紅色和白色兩種,聚合結(jié)果返回有key=red和key=white兩個桶(buckets)肺缕。
注釋3:先按照color:red過濾左医,然后再按照model字段聚合,即查詢紅色的同木、華為品牌的手機浮梢,并且按照model分類聚合,聚合結(jié)果返回key=mate40和key=p30兩個桶(buckets)彤路。
注釋4:搜索查詢只查詢顏色為紅色的秕硝,Post過濾器應(yīng)用于搜索查詢,不會影響聚合操作洲尊,即不影響操作2和3远豺。

重新計分器

查詢重新計分器(rescorer)只對query和post_filter階段返回的Top-K結(jié)果執(zhí)行第二個查詢。
通過window_size參數(shù)控制每個分片上被檢查的文檔數(shù)量坞嘀,默認值是10躯护。
默認情況下,原始查詢和rescore查詢的分數(shù)被線性組合(可配置)丽涩,從而為每個文檔生成最終的_score棺滞,原始查詢和rescore查詢的相對重要性可以分別用query_weight參數(shù)和rescore_query_weight參數(shù)來控制,兩者都默認為1矢渊。

  • 通過參數(shù)rescore來設(shè)置继准,操作示例如下:
POST /my_index_phone/_search
{
   "query" : {
      "match" : {
         "model" : {
            "operator" : "or",
            "query" : "p30"
         }
      }
   },
   "rescore" : [ {
      "window_size" : 100,
      "query" : {
         "rescore_query" : { // 1
            "match_phrase" : {
               "color" : {
                  "query" : "white",
                  "slop" : 2
               }
            }
         },
         "query_weight" : 0.7, 
         "rescore_query_weight" : 1.2 //2
      }
   }]
}

注釋1:rescore查詢顏色為白色的短語查詢并計算得分,該得分線性組合原始得分來決定最終得分矮男。
注釋2:rescore查詢相關(guān)性權(quán)重設(shè)置移必。

通過參數(shù)score_mode配置得分組合的方式,score_mode配置值如下:

  • total:原始查詢得分和rescore查詢得分累加昂灵,默認值避凝。
  • multiply:原始查詢得分和rescore查詢得分相乘,需要使用函數(shù)查詢rescore眨补。
  • avg:原始查詢得分和rescore查詢得分平均值管削。
  • max:原始查詢得分和rescore查詢得分取最大值。
  • min:原始查詢得分和rescore查詢得分取最小值撑螺。

并且Elasticsearch支持按順序多個rescore查詢含思,示例如下:

POST /my_index_phone/_search
{
   "query" : {
      "match" : {
         "brand" : {
            "operator" : "or",
            "query" : "huawei"
         }
      }
   },
   "rescore" : [ {
        "window_size" : 100,
        "query" : {
           "rescore_query" : {
              "match_phrase" : {
                 "color" : {
                    "query" : "red",
                    "slop" : 2
                 }
              }
           },
           "query_weight" : 1,
           "rescore_query_weight" : 2
        }
     },
      {
        "window_size" : 10,
        "query" : {
           "score_mode": "multiply",
           "rescore_query" : {
              "function_score" : {
                 "script_score": {
                    "script": {
                      "source": "Math.log10(_score + 2)"
                    }
                 }
              }
           }
        }
     }
   ]
}
  • 第一個rescore獲取查詢的結(jié)果,第二個rescore獲取第一個rescore的結(jié)果,以此類推含潘。第二次rescore將“看到”第一次rescore所做的排序饲做,因此可以在第一次rescore時使用一個大窗口將文檔拉到一個小窗口中進行第二次rescore。

3. 高亮

高亮器(Highlighters)能夠?qū)⑺阉鹘Y(jié)果中的一個或多個字段加上代碼片段以突出顯示遏弱。當(dāng)要請求高亮顯示時盆均,Elasticsearch響應(yīng)會為每個搜索命中集包含一個額外的高亮元素,其中包括高亮顯示的字段和高亮顯示的片段漱逸。

  • 例如泪姨,將查詢匹配的搜索命中集中model字段值高亮顯示,示例如下:
GET /my_index_phone/_search
{
  "query": {
    "match": { "model": "p30" }
  },
  "highlight": {
    "fields": {
      "model": {}
    }
  }
}

返回結(jié)果片段:

 ...
{
    "_index" : "my_index_phone",
    "_type" : "_doc",
    "_id" : "3",
    "_score" : 0.4700036,
    "_source" : {
      "brand" : "huawei",
      "color" : "white",
      "model" : "p30"
    },
    "highlight" : {
      "model" : [
        "<em>p30</em>" //1
      ]
    }
}
...

注釋1:高亮顯示饰抒,默認加上<em></em>標(biāo)簽肮砾。

高亮器類型

高亮器類型有三種:unified,plain和fvh袋坑≌檀Γ可以通過type參數(shù)來修改每個字段的高亮器類型,Elasticsearch高亮器默認unified枣宫。

  • unified: unified highlighter使用Lucene的統(tǒng)unified highlighter婆誓。該高亮器將文本分解成句子,并使用BM25算法給單個句子打分镶柱。它還支持精確短語和多詞條(模糊旷档、前綴、正則表達式)突出顯示歇拆。這是默認高亮器鞋屈。示例如下圖所示:
  • plain: plain highlighter使用標(biāo)準的Lucene highlighter。它嘗試從理解短語查詢中的單詞重要性和任何單詞定位標(biāo)準方面反映查詢匹配邏輯故觅。示例如下圖所示:
  • fvh: fast vector highlighter使用Lucene fast vector highlighter厂庇。可以在映射(mapping)中將字段上的參數(shù)term_vector設(shè)置為with_positions_offsets的來使用此高亮顯示输吏。該高亮器具有下列特點:
    (1)可以用一個邊界掃描(boundary_scanner)來自定義权旷。
    (2)需要將參數(shù)term_vector設(shè)置為with_positions_offsets,這樣會增加索引的大小贯溅。
    (3)可以將多個字段的匹配項合并到一個結(jié)果中拄氯。具體可了解matched_fields。
    (4)可以分配不同的權(quán)重在不同位置的匹配它浅,允許像短語匹配被排序在詞條匹配上面突出顯示一個增強查詢译柏,增強短語匹配超過詞條匹配。
    示例如下圖所示:

高亮器設(shè)置

高亮器設(shè)置(Highlighting settings)可以在全局級別設(shè)置姐霍,并在字段級別覆蓋鄙麦。具體參數(shù)設(shè)置有以下:

boundary_chars

包含每個邊界字符的字符串典唇。默認為.,!? \t\n。

boundary_max_scan

掃描邊界字符的范圍胯府。默認為20介衔。

boundary_scanner

指定如何切分突出顯示的片段(fragments),有三個設(shè)置值:chars骂因、sentence或word炎咖。僅適用于unified和fvh高亮器。unified高亮器默認該設(shè)置值為sentence寒波,fvh高亮器默認該設(shè)置值為chars塘装。

  • chars
    使用由boundary_chars指定的字符高亮顯示邊界。boundary_max_scan設(shè)置控制掃描邊界字符的范圍影所。僅對fvh高亮器有效。
  • sentence
    根據(jù)Java的BreakIterator來確定下一個句子邊界處切分突出顯示的片段(fragments)僚碎『锩洌可以通過boundary_scanner_locale指定要使用的語言環(huán)境。
  • word
    根據(jù)Java的BreakIterator來確定下一個單詞邊界處切分突出顯示的片段(fragments)勺阐【碇校可以通過boundary_scanner_locale指定要使用的語言環(huán)境。
boundary_scanner_locale

控制用于搜索句子和單詞邊界的語言環(huán)境渊抽。這個參數(shù)采用語言標(biāo)記的形式蟆豫,例如±撩疲“en-us”十减、“-fr”、“ja-JP”愤估。更多信息可以在 Locale Language Tag
文檔中找到帮辟。默認值是local.root。

encoder

指示代碼段是否應(yīng)該用HTML編碼:default(無編碼)或html (HTML-轉(zhuǎn)義代碼段文本玩焰,然后插入高亮顯示標(biāo)記)由驹。

fields

指定要檢索高亮顯示的字段∥粼埃可以使用通配符來指定字段蔓榄。例如,可以指定content*來高亮顯示所有以content開頭的text和keyword字段默刚。示例如下:

GET my_index_01/_search
{
  "query": {
    "match": {
      "content": "紅豆生南國甥郑。"
    }
  },
   "highlight": {
    "fields": {
      "content*": {"type": "plain"}
    }
  }
}
force_source

即使字段是單獨存儲的,也要基于字段_source高亮顯示羡棵。默認值為false壹若。

fragmenter

指定文本應(yīng)該如何在高亮顯示片段中拆分:simplespan。僅對plain highlighter有效。默認值為span店展。

  • simple:將文本分隔成大小相同的片段养篓。
  • span:將文本分割成大小相同的片段,但盡量避免在高亮顯示的詞條(term)之間分割文本赂蕴。
fragment_offset

控制開始高亮顯示的頁邊距柳弄。僅對fvh高亮器有效。

fragment_size

以字符為單位高亮顯示的片段大小概说。默認為100碧注。

highlight_query

高亮顯示搜索查詢以外的其他查詢的匹配項。這在使用rescore查詢時特別有用糖赔,因為默認情況下高亮顯示不會考慮rescore查詢萍丐。

matched_fields

如果沒有要高亮顯示的匹配片段,則希望從字段的開始位置返回的文本數(shù)量放典。默認值為0(不返回任何內(nèi)容)逝变。

number_of_fragments

返回的最大片段數(shù)。如果片段數(shù)設(shè)置為0奋构,則不返回片段壳影。相反,整個字段內(nèi)容將高亮顯示并返回弥臼。當(dāng)需要高亮顯示短文本(如標(biāo)題或地址)時宴咧,這很方便,但不需要分割径缅。如果number_of_fragments為0掺栅,則會忽略fragment_size。默認為5芥驳。

order

當(dāng)設(shè)置值為score時柿冲,根據(jù)得分對高亮顯示的片段進行排序。默認情況下(默認值none)兆旬,片段將按照它們在字段中出現(xiàn)的順序輸出假抄。

phrase_limit

控制文檔中要考慮的匹配短語的數(shù)量。防止fvh高亮器分析太多的短語和消耗太多的內(nèi)存丽猬。在使用matched_fields時宿饱,將考慮每個匹配字段的phrase_limit。提高限制值會增加查詢時間并消耗更多內(nèi)存脚祟。只支持fvh高亮器谬以。默認為256。

pre_tags

與post_tags一起使用由桌,定義用于高亮顯示文本的HTML標(biāo)記为黎。默認情況下邮丰,高亮顯示的文本被包裹在<em>和</em>標(biāo)簽中。指定為字符串?dāng)?shù)組铭乾。

post_tags

與pre_tags一起使用剪廉,定義用于高亮顯示文本的HTML標(biāo)記。默認情況下炕檩,高亮顯示的文本被包裝在<em>和</em>標(biāo)簽中斗蒋。指定為字符串?dāng)?shù)組。操作示例如下:

GET my_index_01/_search
{
  "query": {
    "match": {
      "content": "紅豆生南國"
    }
  },
   "highlight": {
    "fields": {
      "content*": {"type": "plain"}
    },
    "pre_tags": ["<em>"],
    "post_tags": ["</em>"]
  }
}
require_field_match

默認情況下(默認值為true)笛质,只有包含查詢匹配的字段才會高亮顯示泉沾。如果將require_field_match設(shè)置為false,那么會高亮顯示所有字段妇押。

tags_schema

通過使用內(nèi)置標(biāo)簽?zāi)J剑╰ags schema)設(shè)置樣式跷究。該模式定義了以下pre_tags的樣式并將post_tags定義為</em>。

<em class="hlt1">, <em class="hlt2">, <em class="hlt3">,
<em class="hlt4">, <em class="hlt5">, <em class="hlt6">,
<em class="hlt7">, <em class="hlt8">, <em class="hlt9">,
<em class="hlt10">
type

使用的高亮器類型:unified敲霍,plain和fvh揭朝。

高亮樣例

先創(chuàng)建索引并索引數(shù)據(jù)。

PUT /my_index_01
{
  "mappings": {
    "properties": {
       "content": {
        "type": "text"
      },
      "name":{
        "type": "text"
      }
    }
  }
}
POST /my_index_01/_create/1
{
  "content": "Quick Brown Fox色冀,Quick White Fox, Quick gray Fox",
  "name": "Fox"
}
高亮所有字段

通過require_field_match參數(shù)設(shè)置false來高亮所有字段,示例如下:

GET my_index_01/_search
{
  "query": {
    "match": {
      "name": "Fox"
    }
  },
   "highlight": {
    "require_field_match": false,
    "fields": {
      "name": { },
      "content": {}
    }
  }
}
配置高亮標(biāo)簽樣式

通過tags_schema參數(shù)設(shè)置標(biāo)簽樣式柱嫌,示例如下:

GET my_index_01/_search
{
  "query": {
    "match": {
      "name": "Fox"
    }
  },
   "highlight": {
    "tags_schema" : "styled",
    "fields": {
      "name": { }
    }
  }
}
控制高亮片段

每個高亮顯示的字段可以控制其高亮顯示的片段的大小(默認為100)锋恬,以及返回的最大片段數(shù)(默認為5)。示例如下:

GET my_index_01/_search
{
  "query": {
    "match": {
      "content": "Fox"
    }
  },
   "highlight": {
    "fields": {
      "content": {"fragment_size" : 15, "number_of_fragments" : 2}
    }
  }
}
為plain高亮器指定fragmenter

通過fragmenter參數(shù)和type參數(shù)設(shè)置编丘。示例如下:

GET my_index_01/_search
{
  "query": {
    "match_phrase": { "content": "Brown Fox" }
  },
  "highlight": {
    "fields": {
      "content": {
        "type": "plain",
        "fragment_size": 15,
        "number_of_fragments": 2,
        "fragmenter": "simple"
      }
    }
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末与学,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嘉抓,更是在濱河造成了極大的恐慌索守,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抑片,死亡現(xiàn)場離奇詭異卵佛,居然都是意外死亡,警方通過查閱死者的電腦和手機敞斋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門截汪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人植捎,你說我怎么就攤上這事衙解。” “怎么了焰枢?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵蚓峦,是天一觀的道長舌剂。 經(jīng)常有香客問我庸诱,道長做瞪,這世上最難降的妖魔是什么淤击? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任恨樟,我火速辦了婚禮侣灶,結(jié)果婚禮上聪姿,老公的妹妹穿的比我還像新娘哎垦。我一直安慰自己努咐,他們只是感情好角虫,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布沾谓。 她就那樣靜靜地躺著,像睡著了一般戳鹅。 火紅的嫁衣襯著肌膚如雪均驶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天枫虏,我揣著相機與錄音妇穴,去河邊找鬼。 笑死隶债,一個胖子當(dāng)著我的面吹牛腾它,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播死讹,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼瞒滴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了赞警?” 一聲冷哼從身側(cè)響起妓忍,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎愧旦,沒想到半個月后世剖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡笤虫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年旁瘫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琼蚯。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡境蜕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出凌停,到底是詐尸還是另有隱情粱年,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布罚拟,位于F島的核電站台诗,受9級特大地震影響完箩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拉队,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一弊知、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧粱快,春花似錦秩彤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鳍咱,卻和暖如春降盹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谤辜。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工蓄坏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丑念。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓涡戳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親脯倚。 傳聞我的和親對象是個殘疾皇子妹蔽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345