如何使Elasticsearch匹配包含句点作为单词分隔符的文档

时间:2018-07-17 07:12:20

标签: elasticsearch full-text-search

我在elasticsearch中有文档,其中包含.,即full stop作为标题中的单词分隔符。

例如title

The.Handmaids.Tale.S02E05.WEBRip.x264-TBS[ettv]

因此,如果我搜索"The Handmaids Tale S02E05 WEBRip"

我的elasticsearch查询成为

$params['body']['query']['bool']['must'][]['match']['title'] = The
$params['body']['query']['bool']['must'][]['match']['title'] = Handmaids
$params['body']['query']['bool']['must'][]['match']['title'] = Tale
$params['body']['query']['bool']['must'][]['match']['title'] = S02E05
$params['body']['query']['bool']['must'][]['match']['title'] = WEBRip

此查询不会返回上述文档。

所以我如何使elasticsearch忽略。 aka标题中的句号,然后在我搜索“ The Handmaids Tale S02E05 WEBRip”时返回该文档?

我正在使用最新的Elasticsearch 6.3

我当前的index mapping

"mappings": {
    "content": { 
        "properties": { 
            "title":{ 
                "type":     "text",
                "fields": {
                    "raw": { 
                        "type":  "keyword"
                    }
                }
            },
            "tags":         { "type": "text" },
            "category":     { "type": "short" },
            "sub_category": { "type": "short" },
            "size":         { "type": "long" },
            "uploaders":      { "type": "integer" },
            "downloaders":      { "type": "integer" },
            "upload_date":  {
                "type":   "date",
                "format": "yyyy-MM-dd HH:mm:ss"
            },
            "uploader":{
                        "type":     "text",
                        "fields":   {
                                    "raw": { 
                                        "type":  "keyword"
                                    }
                        }
            }
        }
    }
}

update1:​​来自此https://stackoverflow.com/a/40136928/1642018

我想到了这个

"settings": {
"analysis": {
  "analyzer": {
    "my_analyzer": {
      "type":      "custom",
      "tokenizer": "standard",
      "char_filter": [
        "replace_dot"
      ]
    }
  },
  "char_filter": {
    "replace_dot": {
      "type": "pattern_replace",
      "pattern": "\\.",
      "replacement": " "
    }
  }
}
},

以及类似的映射

"title":{ 
    "type":     "text",
     "analyzer": "my_analyzer",
    "fields": {
        "raw": { 
            "type":  "keyword"
        }
    }
},

我创建了一个新索引,但仍然没有运气 我用"title": {"type":"string", "analyzer":"my_analyzer"}定义了映射-但无济于事。

如果我针对新的分析器在新索引上调用localhost:9200/_analyze,则该字符串将被完美分解。

例如

curl -X POST "localhost:9200/newindex3/_analyze?pretty" -H 'Content-Type: application/json' -d'
{
  "analyzer": "my_analyzer",
  "text": "John.Doe.mill.dane"
}
'
{
  "tokens" : [
    {
      "token" : "John",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "Doe",
      "start_offset" : 5,
      "end_offset" : 8,
      "type" : "<ALPHANUM>",
      "position" : 1
    },
    {
      "token" : "mill",
      "start_offset" : 9,
      "end_offset" : 13,
      "type" : "<ALPHANUM>",
      "position" : 2
    },
    {
      "token" : "dane",
      "start_offset" : 14,
      "end_offset" : 18,
      "type" : "<ALPHANUM>",
      "position" : 3
    }
  ]
}

但是搜索仍然没有返回预期的文档。

我想念什么?


update2:现在,我正要在插入索引之前通过使用

'title' => str_replace('.', ' ', $results[$i]['title'])

1 个答案:

答案 0 :(得分:0)

您首先需要了解分析器在Elasticsearch中的工作方式。

由于您在字段标题的映射中未提及任何分析器,因此将使用标准分析器。

现在,您需要查看标准分析器如何根据您的文本生成令牌,即它如何存储令牌以进行搜索

这是您发短信的一个例子

GET _analyze
{
  "text": ["The.Handmaids.Tale.S02E05.WEBRip.x264-TBS[ettv]"],
  "analyzer": "standard"
}

下面是结果

{
  "tokens": [
    {
      "token": "the.handmaids.tale.s02e05",
      "start_offset": 0,
      "end_offset": 25,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "webrip.x264",
      "start_offset": 26,
      "end_offset": 37,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "tbs",
      "start_offset": 38,
      "end_offset": 41,
      "type": "<ALPHANUM>",
      "position": 2
    },
    {
      "token": "ettv",
      "start_offset": 42,
      "end_offset": 46,
      "type": "<ALPHANUM>",
      "position": 3
    }
  ]
}

这是您的查询无法工作的原因,因为它可以对令牌进行完全匹配。

您需要做的是制作一个如下所示的自定义分析器

PUT test_pattern
{
  "settings": {
    "number_of_shards": 1, 
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "type":      "pattern",
          "pattern":   "\\."
        }
      }
    }
  }
}

并将映射中的分析器更改为 my_analyzer

"mappings": {
    "content": {
      "properties": {
        "title": {
          "type": "text",
          "analyzer":"my_analyzer",
          "fields": {
            "raw": {
              "type": "keyword"
            }
          }
        },
        "tags": {
          "type": "text"
        },
        "category": {
          "type": "short"
        },
        "sub_category": {
          "type": "short"
        },
        "size": {
          "type": "long"
        },
        "uploaders": {
          "type": "integer"
        },
        "downloaders": {
          "type": "integer"
        },
        "upload_date": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss"
        },
        "uploader": {
          "type": "text",
          "fields": {
            "raw": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }