### 處理 Null 值
回到我們早期的示例,在文檔中有一個多值的字段 `tags`,一個文檔可能包含一個或多個標簽,或根本沒有標簽。如果一個字段沒有值,它是怎么儲存在倒排索引中的?
這是一個取巧的問題,因為答案是它根本沒有存儲。讓我們從看一下前幾節的倒排索引:
| Token | DocIDs |
|---------------|--------|
|`open_source` | `2` |
|`search` | `1`,`2`|
你怎么可能儲存一個在數據結構不存在的字段呢?倒排索引是標記和包含它們的文檔的一個簡單列表。假如一個字段不存在,它就沒有任何標記,也就意味著它無法被倒排索引的數據結構表達出來。
本質上來說,`null`,`[]`(空數組)和 `[null]` 是相等的。它們都不存在于倒排索引中!
顯然,這個世界卻沒有那么簡單,數據經常會缺失字段,或包含空值或空數組。為了應對這些情形,Elasticsearch 有一些工具來處理空值或缺失的字段。
#### `exists` 過濾器
工具箱中的第一個利器是 `exists` 過濾器,這個過濾器將返回任何包含這個字段的文檔,讓我們用標簽來舉例,索引一些示例文檔:
```json
POST /my_index/posts/_bulk
{ "index": { "_id": "1" }}
{ "tags" : ["search"] } <1>
{ "index": { "_id": "2" }}
{ "tags" : ["search", "open_source"] } <2>
{ "index": { "_id": "3" }}
{ "other_field" : "some data" } <3>
{ "index": { "_id": "4" }}
{ "tags" : null } <4>
{ "index": { "_id": "5" }}
{ "tags" : ["search", null] } <5>
```
<!-- SENSE: 080_Structured_Search/30_Exists_missing.json -->
<1> `tags` 字段有一個值
<2> `tags` 字段有兩個值
<3> `tags` 字段不存在
<4> `tags` 字段被設為 `null`
<5> `tags` 字段有一個值和一個 `null`
結果我們 `tags` 字段的倒排索引看起來將是這樣:
| Token | DocIDs |
|--------------|-------------|
|`open_source` | `2` |
|`search` | `1`,`2`,`5` |
我們的目標是找出所有設置了標簽的文檔,我們不關心這個標簽是什么,只要它存在于文檔中就行。在 SQL 語法中,我們可以用 `IS NOT NULL` 查詢:
```sql
SELECT tags
FROM posts
WHERE tags IS NOT NULL
```
在 Elasticsearch 中,我們使用 `exists` 過濾器:
```json
GET /my_index/posts/_search
{
"query" : {
"filtered" : {
"filter" : {
"exists" : { "field" : "tags" }
}
}
}
}
```
<!-- SENSE: 080_Structured_Search/30_Exists_missing.json -->
查詢返回三個文檔:
```json
"hits" : [
{
"_id" : "1",
"_score" : 1.0,
"_source" : { "tags" : ["search"] }
},
{
"_id" : "5",
"_score" : 1.0,
"_source" : { "tags" : ["search", null] } <1>
},
{
"_id" : "2",
"_score" : 1.0,
"_source" : { "tags" : ["search", "open source"] }
}
]
```
<1> 文檔 5 雖然包含了一個 `null` 值,仍被返回了。這個字段存在是因為一個有值的標簽被索引了,所以 `null` 對這個過濾器沒有影響
結果很容易理解,所以在 `tags` 字段中有值的文檔都被返回了。只排除了文檔 3 和 4。
#### `missing` 過濾器
`missing` 過濾器本質上是 `exists` 的反義詞:它返回沒有特定字段值的文檔,像這條 SQL 一樣:
```sql
SELECT tags
FROM posts
WHERE tags IS NULL
```
讓我們在前面的例子中用 `missing` 過濾器來取代 `exists`:
```json
GET /my_index/posts/_search
{
"query" : {
"filtered" : {
"filter": {
"missing" : { "field" : "tags" }
}
}
}
}
```
<!-- SENSE: 080_Structured_Search/30_Exists_missing.json -->
如你所愿,我們得到了兩個沒有包含標簽字段的文檔:
```json
"hits" : [
{
"_id" : "3",
"_score" : 1.0,
"_source" : { "other_field" : "some data" }
},
{
"_id" : "4",
"_score" : 1.0,
"_source" : { "tags" : null }
}
]
```
什么時候 null 才表示 null
有時你需要能區分一個字段是沒有值,還是被設置為 `null`。用上面見到的默認行為無法區分這一點,數據都不存在了。幸運的是,我們可以將明確的 `null` 值用我們選擇的_占位符_來代替
當指定字符串,數字,布爾值或日期字段的映射時,你可以設置一個 `null_value` 來處理明確的 `null` 值。沒有值的字段仍將被排除在倒排索引外。
當選定一個合適的 `null_value` 時,確保以下幾點:
* 它與字段的類型匹配,你不能在 `date` 類型的字段中使用字符串 `null_value`
* 它需要能與這個字段可能包含的正常值區分開來,以避免真實值和 `null` 值混淆
#### 對象的 `exists/missing`
`exists` 和 `missing` 過濾器同樣能在內聯對象上工作,而不僅僅是核心類型。例如下面的文檔:
```json
{
"name" : {
"first" : "John",
"last" : "Smith"
}
}
```
你可以檢查 `name.first` 和 `name.last` 的存在性,也可以檢查 `name` 的。然而,在【映射】中,我們提到對象在內部被轉成扁平化的鍵值結構,像下面所示:
```json
{
"name.first" : "John",
"name.last" : "Smith"
}
```
所以我們是怎么使用 `exists` 或 `missing` 來檢測 `name` 字段的呢,這個字段并沒有真正存在于倒排索引中。
原因是像這樣的一個過濾器
```json
{
"exists" : { "field" : "name" }
}
```
實際是這樣執行的
```json
{
"bool": {
"should": [
{ "exists": { "field": { "name.first" }}},
{ "exists": { "field": { "name.last" }}}
]
}
}
```
同樣這意味著假如 `first` 和 `last` 都為空,那么 `name` 就是不存在的。
- Introduction
- 入門
- 是什么
- 安裝
- API
- 文檔
- 索引
- 搜索
- 聚合
- 小結
- 分布式
- 結語
- 分布式集群
- 空集群
- 集群健康
- 添加索引
- 故障轉移
- 橫向擴展
- 更多擴展
- 應對故障
- 數據
- 文檔
- 索引
- 獲取
- 存在
- 更新
- 創建
- 刪除
- 版本控制
- 局部更新
- Mget
- 批量
- 結語
- 分布式增刪改查
- 路由
- 分片交互
- 新建、索引和刪除
- 檢索
- 局部更新
- 批量請求
- 批量格式
- 搜索
- 空搜索
- 多索引和多類型
- 分頁
- 查詢字符串
- 映射和分析
- 數據類型差異
- 確切值對決全文
- 倒排索引
- 分析
- 映射
- 復合類型
- 結構化查詢
- 請求體查詢
- 結構化查詢
- 查詢與過濾
- 重要的查詢子句
- 過濾查詢
- 驗證查詢
- 結語
- 排序
- 排序
- 字符串排序
- 相關性
- 字段數據
- 分布式搜索
- 查詢階段
- 取回階段
- 搜索選項
- 掃描和滾屏
- 索引管理
- 創建刪除
- 設置
- 配置分析器
- 自定義分析器
- 映射
- 根對象
- 元數據中的source字段
- 元數據中的all字段
- 元數據中的ID字段
- 動態映射
- 自定義動態映射
- 默認映射
- 重建索引
- 別名
- 深入分片
- 使文本可以被搜索
- 動態索引
- 近實時搜索
- 持久化變更
- 合并段
- 結構化搜索
- 查詢準確值
- 組合過濾
- 查詢多個準確值
- 包含,而不是相等
- 范圍
- 處理 Null 值
- 緩存
- 過濾順序
- 全文搜索
- 匹配查詢
- 多詞查詢
- 組合查詢
- 布爾匹配
- 增加子句
- 控制分析
- 關聯失效
- 多字段搜索
- 多重查詢字符串
- 單一查詢字符串
- 最佳字段
- 最佳字段查詢調優
- 多重匹配查詢
- 最多字段查詢
- 跨字段對象查詢
- 以字段為中心查詢
- 全字段查詢
- 跨字段查詢
- 精確查詢
- 模糊匹配
- Phrase matching
- Slop
- Multi value fields
- Scoring
- Relevance
- Performance
- Shingles
- Partial_Matching
- Postcodes
- Prefix query
- Wildcard Regexp
- Match phrase prefix
- Index time
- Ngram intro
- Search as you type
- Compound words
- Relevance
- Scoring theory
- Practical scoring
- Query time boosting
- Query scoring
- Not quite not
- Ignoring TFIDF
- Function score query
- Popularity
- Boosting filtered subsets
- Random scoring
- Decay functions
- Pluggable similarities
- Conclusion
- Language intro
- Intro
- Using
- Configuring
- Language pitfalls
- One language per doc
- One language per field
- Mixed language fields
- Conclusion
- Identifying words
- Intro
- Standard analyzer
- Standard tokenizer
- ICU plugin
- ICU tokenizer
- Tidying text
- Token normalization
- Intro
- Lowercasing
- Removing diacritics
- Unicode world
- Case folding
- Character folding
- Sorting and collations
- Stemming
- Intro
- Algorithmic stemmers
- Dictionary stemmers
- Hunspell stemmer
- Choosing a stemmer
- Controlling stemming
- Stemming in situ
- Stopwords
- Intro
- Using stopwords
- Stopwords and performance
- Divide and conquer
- Phrase queries
- Common grams
- Relevance
- Synonyms
- Intro
- Using synonyms
- Synonym formats
- Expand contract
- Analysis chain
- Multi word synonyms
- Symbol synonyms
- Fuzzy matching
- Intro
- Fuzziness
- Fuzzy query
- Fuzzy match query
- Scoring fuzziness
- Phonetic matching
- Aggregations
- overview
- circuit breaker fd settings
- filtering
- facets
- docvalues
- eager
- breadth vs depth
- Conclusion
- concepts buckets
- basic example
- add metric
- nested bucket
- extra metrics
- bucket metric list
- histogram
- date histogram
- scope
- filtering
- sorting ordering
- approx intro
- cardinality
- percentiles
- sigterms intro
- sigterms
- fielddata
- analyzed vs not
- 地理坐標點
- 地理坐標點
- 通過地理坐標點過濾
- 地理坐標盒模型過濾器
- 地理距離過濾器
- 緩存地理位置過濾器
- 減少內存占用
- 按距離排序
- Geohashe
- Geohashe
- Geohashe映射
- Geohash單元過濾器
- 地理位置聚合
- 地理位置聚合
- 按距離聚合
- Geohash單元聚合器
- 范圍(邊界)聚合器
- 地理形狀
- 地理形狀
- 映射地理形狀
- 索引地理形狀
- 查詢地理形狀
- 在查詢中使用已索引的形狀
- 地理形狀的過濾與緩存
- 關系
- 關系
- 應用級別的Join操作
- 扁平化你的數據
- Top hits
- Concurrency
- Concurrency solutions
- 嵌套
- 嵌套對象
- 嵌套映射
- 嵌套查詢
- 嵌套排序
- 嵌套集合
- Parent Child
- Parent child
- Indexing parent child
- Has child
- Has parent
- Children agg
- Grandparents
- Practical considerations
- Scaling
- Shard
- Overallocation
- Kagillion shards
- Capacity planning
- Replica shards
- Multiple indices
- Index per timeframe
- Index templates
- Retiring data
- Index per user
- Shared index
- Faking it
- One big user
- Scale is not infinite
- Cluster Admin
- Marvel
- Health
- Node stats
- Other stats
- Deployment
- hardware
- other
- config
- dont touch
- heap
- file descriptors
- conclusion
- cluster settings
- Post Deployment
- dynamic settings
- logging
- indexing perf
- rolling restart
- backup
- restore
- conclusion