正在加载

将精确搜索与词干提取结合使用

Elastic Stack Serverless

在构建搜索应用程序时,词干提取通常是必须的,因为希望对 skiing 的查询能够匹配包含 skiskis 的文档。但是,如果用户想要专门搜索 skiing 呢?通常的做法是使用多字段,以便以两种不同的方式索引相同的内容

 PUT index {
  "settings": {
    "analysis": {
      "analyzer": {
        "english_exact": {
          "tokenizer": "standard",
          "filter": [
            "lowercase"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "body": {
        "type": "text",
        "analyzer": "english",
        "fields": {
          "exact": {
            "type": "text",
            "analyzer": "english_exact"
          }
        }
      }
    }
  }
}

PUT index/_doc/1
{
  "body": "Ski resort"
}

PUT index/_doc/2
{
  "body": "A pair of skis"
}

POST index/_refresh

通过这种设置,在 body 上搜索 ski 将返回两个文档

 GET index/_search {
  "query": {
    "simple_query_string": {
      "fields": [ "body" ],
      "query": "ski"
    }
  }
}
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped" : 0,
    "failed": 0
  },
  "hits": {
    "total" : {
        "value": 2,
        "relation": "eq"
    },
    "max_score": 0.18232156,
    "hits": [
      {
        "_index": "index",
        "_id": "1",
        "_score": 0.18232156,
        "_source": {
          "body": "Ski resort"
        }
      },
      {
        "_index": "index",
        "_id": "2",
        "_score": 0.18232156,
        "_source": {
          "body": "A pair of skis"
        }
      }
    ]
  }
}

另一方面,在 body.exact 上搜索 ski 将仅返回文档 1,因为 body.exact 的分析链不执行词干提取。

 GET index/_search {
  "query": {
    "simple_query_string": {
      "fields": [ "body.exact" ],
      "query": "ski"
    }
  }
}
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped" : 0,
    "failed": 0
  },
  "hits": {
    "total" : {
        "value": 1,
        "relation": "eq"
    },
    "max_score": 0.8025915,
    "hits": [
      {
        "_index": "index",
        "_id": "1",
        "_score": 0.8025915,
        "_source": {
          "body": "Ski resort"
        }
      }
    ]
  }
}

这不容易暴露给最终用户,因为我们需要找到一种方法来确定他们是否正在寻找精确匹配,并相应地重定向到适当的字段。如果只有部分查询需要精确匹配,而其他部分仍应考虑词干提取,该怎么办?

幸运的是,query_stringsimple_query_string 查询具有一个功能,可以解决这个确切的问题:quote_field_suffix。这告诉 Elasticsearch,出现在引号之间的单词将被重定向到另一个字段,请参见下文

 GET index/_search {
  "query": {
    "simple_query_string": {
      "fields": [ "body" ],
      "quote_field_suffix": ".exact",
      "query": "\"ski\""
    }
  }
}
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped" : 0,
    "failed": 0
  },
  "hits": {
    "total" : {
        "value": 1,
        "relation": "eq"
    },
    "max_score": 0.8025915,
    "hits": [
      {
        "_index": "index",
        "_id": "1",
        "_score": 0.8025915,
        "_source": {
          "body": "Ski resort"
        }
      }
    ]
  }
}

在上面的例子中,由于 ski 位于引号之间,因此由于 quote_field_suffix 参数,在 body.exact 字段上搜索了它,因此只有文档 1 匹配。这允许用户根据需要将精确搜索与词干提取搜索混合使用。

注意

如果在 quote_field_suffix 中传递的字段选择不存在,搜索将回退到使用查询字符串的默认字段。

© . All rights reserved.