Elasticsearch 中的通配符搜索或部分匹配

Wilcard search or partial matching in Elastic search

我正在尝试向最终用户提供搜索类型,这更像是 sql 服务器。 我能够针对给定的 sql 场景实施 ES 查询:

select * from table where name like '%pete%' and type != 'xyz and type!='abc'

但是 ES 查询不适用于此 sql 查询

select * from table where name like '%peter tom%' and type != 'xyz and type!='abc'

在我的弹性搜索和通配符查询中,我还需要执行一些布尔过滤查询

{
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "should": [
            {
              "query": {
                "wildcard": {
                  "name": { "value": "*pete*" }
                }
              }
            }
          ],
          "must_not": [
            {
              "match": { "type": "xyz" }
            },
            {
              "match": { "type": "abc" }
            }
          ]
        }
      }
    }
  }
}

上面使用通配符搜索的弹性查询工作正常,并为我提供了所有与 pete 匹配且不属于 xyz 和 abc 类型的文档。但是当我尝试使用由 space 分隔的 2 个单独的词执行通配符时然后相同的查询 returns me empty as shown below.For example

{
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "should": [
            {
              "query": {
                "wildcard": {
                  "name": { "value": "*peter tom*" }
                }
              }
            }
          ],
          "must_not": [
            {
              "match": { "type": "xyz" }
            },
            {
              "match": { "type": "abc" }
            }
          ]
        }
      }
    }
  }
}

我的映射如下:

{
  "properties": {
    "name": {
      "type": "string"
    },
    "type": {
      "type": "string"
    }
  }
}

我应该使用什么查询才能对 spaces

分隔的单词进行通配符搜索

嗯,我的解决方案并不完美,而且我不确定性能。所以你应该自己尝试一下:)

这是 es 5 版本

PUT likequery
{
  "mappings": {
    "typename": {
      "properties": {
        "name": {
          "type": "string",
          "fields": {
            "raw": {
              "type": "keyword"
            }
          }
        },
        "type": {
          "type": "string"
        }
      }
    }
  }
}

在 ES 2.1 中将 "type": "keyword" 更改为 "type": "string", "index": "not_analyzed"

PUT likequery/typename/1
{
  "name": "peter tomson"
}

PUT likequery/typename/2
{
  "name": "igor tkachenko"
}

PUT likequery/typename/3
{
  "name": "taras shevchenko"
}

查询 区分大小写

POST likequery/_search
{
  "query": {
    "regexp": {
      "name.raw": ".*taras shev.*"
    }
  }
}

回应

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "likequery",
        "_type": "typename",
        "_id": "3",
        "_score": 1,
        "fields": {
          "raw": [
            "taras shevchenko"
          ]
        }
      }
    ]
  }
}

PS。我再次不确定此查询的性能,因为它将使用扫描而不是索引。

最有效的解决方案是利用 ngram tokenizer 来标记 name 字段的部分内容。例如,如果您有一个像 peter tomson 这样的名称,ngram 分词器将像这样对其进行分词和索引:

  • pe
  • 宠物
  • 皮特
  • 彼得
  • 彼得
  • 彼得到
  • 彼得汤姆
  • 彼得汤姆斯
  • 彼得·汤姆索
  • 汤臣
  • 三汤臣
  • 二汤臣
  • r 汤臣
  • 汤臣
  • 汤臣
  • 欧姆森
  • mson
  • 儿子

因此,当它被编入索引后,搜索这些标记中的任何一个都会检索到您的文档,其中包含 peter thomson

让我们创建索引:

PUT likequery
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_ngram_analyzer": {
          "tokenizer": "my_ngram_tokenizer"
        }
      },
      "tokenizer": {
        "my_ngram_tokenizer": {
          "type": "nGram",
          "min_gram": "2",
          "max_gram": "15"
        }
      }
    }
  },
  "mappings": {
    "typename": {
      "properties": {
        "name": {
          "type": "string",
          "fields": {
            "search": {
              "type": "string",
              "analyzer": "my_ngram_analyzer"
            }
          }
        },
        "type": {
          "type": "string",
          "index": "not_analyzed"
        }
      }
    }
  }
}

然后您将能够使用简单且非常高效的 term 查询进行这样的搜索:

POST likequery/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "name.search": "peter tom"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "type": "xyz"
          }
        },
        {
          "match": {
            "type": "abc"
          }
        }
      ]
    }
  }
}