Elasticsearch(八)搜索优化

Elasticsearch: 6.4.2

1. 理解字段分析过程

一个常被问到的问题是,为什么指定的文档没有被搜索到。很多情况下,这都归因于映射的定义和分析例程的配置存在问题。针对分析过程的调试,Elasticsearch提供了专用的REST API。

GET /_analyze
{
  "analyzer": "standard",   # 可以替换成自定义的analyzer
  "text": "crime and publishment"
}
# 使用一个分词器和两个过滤器 
GET _analyze
{
  "tokenizer" : "keyword",
  "filter" : ["lowercase"],
  "char_filter" : ["html_strip"],
  "text" : "this is a <b>test</b>"
}
2. 解释查询

给出有关文档相关度得分计算的详细信息,以解释为什么会匹配成功。

# 针对特定文档的分析
GET /cars/doc/8/_explain?q=jeep
# 针对文本信息的分析
GET _analyze
{
  "tokenizer" : "standard",
  "filter" : ["snowball"],
  "text" : "detailed output",
  "explain" : true,
  "attributes" : ["keyword"] 
}
3. 用加权查询影响得分

Boost(权值):在计算得分过程中使用的附加权值,可在如下位置使用:

  • 查询:告诉搜索引擎指定的查询比其他查询更重要
  • 字段:指定文档中某些字段对用户很重要
  • 文档:某些文档很重要
3.1 在查询中使用权值

例如:

# 字段重要程度:from、to、subject
GET /emails/doc/_search
{
  "query": {
    "query_string": {
      "fields": ["from^5", "to^3", "subject"], 
      "query": "Bourne"
    }
  }
}
3.2 修改得分

constant_score

包装另一个查询子句,为每个文档返回得分等于boost值。

GET /cars/doc/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "match": {
          "name": "bmw jeep"
        }
      },
      "boost": 1.2
    }
  }
}

Boosting查询

Boosting查询与Bool查询中的NOT的不同:后者过滤掉满足NOT查询语句的文档,而前者仍然选择不被期望的文档,只是讲它们的得分降低。

GET /cars/doc/_search
{
  "query": {
    "boosting": {
      "positive": {
        "match_all": {}
      },
      "negative": {
        "term": {
          "name": {
            "value": "jeep"
          }
        }
      },
      "negative_boost": 0.2
    }
  }
}

Function查询

boost参数设置每个文档的得分,然后对于满足functions参数中子查询条件的文档根据boost_mode、boost、weight计算新得分;

当存在多个function且某个文档满足多个function时该文档的得分为:先计算满足各个function后的每个得分,然后由score_mode参数计算最终等分。其中score_mode取值:multiply、sum、avg、first、max、min。

GET /cars/doc/_search
{
  "query": {
    "function_score": {
      "boost": 5,
      "max_boost": 50,
      "score_mode": "max",
      "boost_mode": "multiply",
      "query": {
        "match_all": {}
      },
      "functions": [
        {
          "filter": {
            "match": {"name": "jeep"}
          },
          "weight": 4
        }
      ]
    }
  }
}
4. 具有相同含义的词
4.1 同义词(synonym)过滤器

基于数组定义

PUT /test_index
{
    "settings": {
        "index" : {
            "analysis" : {
                "analyzer" : {
                    "synonym" : {
                        "tokenizer" : "standard",
                        "filter" : ["my_stop", "synonym"]
                    }
                },
                "filter" : {
                    "synonym" : {
                        "type" : "synonym",
                        "lenient": true,
                        "synonyms" : ["foo, bar => baz"]
                    }
                }
            }
        }
    }
}

基于文件定义:文件路径是相对于Elasticsearch安装目录下config目录的。

PUT /test_index
{
    "settings": {
        "index" : {
            "analysis" : {
                "analyzer" : {
                    "synonym" : {
                        "tokenizer" : "whitespace",
                        "filter" : ["synonym"]
                    }
                },
                "filter" : {
                    "synonym" : {
                        "type" : "synonym",
                        "synonyms_path" : "analysis/synonym.txt"
                    }
                }
            }
        }
    }
}
4.2 同义词定义规则

默认使用Apache solr的同义词方案。

同义词显式定义

i-pod, i pod => ipod,
sea biscuit, sea biscit => seabiscuit

同义词等式定义

ipod, i-pod, i pod
foozball , foosball
universe , cosmos
lol, laughing out loud

扩展同义词

如果同义词过滤器中属性expand=true,则所有同义词被扩展为所有单词全部等价的形式。

ipod, i-pod, i pod => ipod, i-pod, i pod
5. 跨度查询

跨度是指在一个字段中开始和结束的词条位置。

span_term

GET /_search
{
    "query": {
        "span_term" : { "user" : "kimchy" }
    }
}

span_multi

包装一个term、range、prefix、wildcard、regexp或fuzzy查询。

GET /_search
{
    "query": {
        "span_multi":{
            "match":{
                "prefix" : { "user" :  { "value" : "ki" } }
            }
        }
    }
}

span_first

只允许返回在字段的前几个位置上匹配查询条件的文档。

# 查询在user字段前三个位置出现kimchy的文档
GET /_search
{
    "query": {
        "span_first" : {
            "match" : {
                "span_term" : { "user" : "kimchy" }
            },
            "end" : 3
        }
    }
}

span_near

可以在有多个其他跨度彼此接近时对文档进行搜索,该查询也是一个能将其他跨度查询包装起来的复合查询。

# slop:控制在跨度之间允许的词项的数量
# in_order: 限制匹配顺序;true时按照查询定义的顺序匹配文档
# 该示例查询message字段包含world everyone的文档。
GET /_search
{
    "query": {
        "span_near" : {
            "clauses" : [
                { "span_term" : { "message" : "world" } },
                { "span_term" : { "message" : "everyone" } }
            ],
            "slop" : 0,
            "in_order" : true
        }
    }
}

span_or

# 获取在message字段前两个位置处有world或者离everyone不超过一个位置处含有world的文档。
GET /_search
{
  "query": {
    "span_near": {
      "clauses": [
        {
          "span_first": {
            "match": {
              "span_term": {
                "message": {
                  "value": "world"
                }
              }
            },
            "end": 2
          }
        },
        {
          "span_near": {
            "clauses": [
              {
                "span_term": {
                  "message": {
                    "value": "world"
                  }
                }
              },
              {
                "span_term": {
                  "message": {
                    "value": "everyone"
                  }
                }
              }
            ],
            "slop": 1,
            "in_order": true
          }
        }
      ],
      "slop": 0,
      "in_order": true
    }
  }
}

span_not

include参数指定了哪个跨度查询应该被匹配;exclude参数指定了不与include部分重叠的跨度查询。

# 返回在message字段中匹配了由breaks词项构造的span_term查询的所有文档,然后再定义一个匹配了world和everyone并且最大位置间距为1的跨度,当该跨度与第一个跨度查询重叠时,排除掉所有重叠部分的文档。
GET /_search
{
  "query": {
    "span_not": {
      "include": {
        "span_term": {
          "message": {
            "value": "breaks"
          }
        }
      },
      "exclude": {
        "span_near": {
          "clauses": [
            {
              "span_term": {
                "message": {
                  "value": "world"
                }
              }
            },
            {
              "span_term": {
                "message": {
                  "value": "everyone"
                }
              }
            }
          ],
          "slop": 1
        }
      }
    }
  }
}

span_containing

查询内部有big和little两个字查询,仅返回big匹配的结果中包含little匹配结果的文档;从大到小包含

GET /_search
{
    "query": {
        "span_containing" : {
            "little" : {
                "span_term" : { "field1" : "foo" }
            },
            "big" : {
                "span_near" : {
                    "clauses" : [
                        { "span_term" : { "field1" : "bar" } },
                        { "span_term" : { "field1" : "baz" } }
                    ],
                    "slop" : 5,
                    "in_order" : true
                }
            }
        }
    }
}

span_within

与span_containing类似,从小到大包含。

GET /_search
{
    "query": {
        "span_within" : {
            "little" : {
                "span_term" : { "field1" : "foo" }
            },
            "big" : {
                "span_near" : {
                    "clauses" : [
                        { "span_term" : { "field1" : "bar" } },
                        { "span_term" : { "field1" : "baz" } }
                    ],
                    "slop" : 5,
                    "in_order" : true
                }
            }
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值