用于连字符,下划线和数字的Elasticsearch自定义分析器

时间:2014-08-11 13:31:55

标签: elasticsearch tokenize analysis

不可否认,我不是那么精通ES的分析部分。这是索引布局:

{
    "mappings": {
        "event": {
            "properties": {
                "ipaddress": {
                    "type": "string"
                },
                "hostname": {
                    "type": "string",
                    "analyzer": "my_analyzer",
                    "fields": {
                        "raw": {
                            "type": "string",
                            "index": "not_analyzed"
                        }
                    }
                }
            }
        }
    },
    "settings": {
        "analysis": {
            "filter": {
                "my_filter": {
                    "type": "word_delimiter",
                    "preserve_original": true
                }
            },
            "analyzer": {
                "my_analyzer": {
                    "type": "custom",
                    "tokenizer": "whitespace",
                    "filter": ["lowercase", "my_filter"]
                }
            }
        }
    }
}

您可以看到我尝试将自定义分析器用于主机名字段。当我使用此查询查找名为“WIN_1”的主机时,这种方法有效:

{
    "query": {
        "match": {
            "hostname": "WIN_1"
        }
    }
}

问题是它还会返回任何包含1的主机名。使用_analyze端点,我可以看到数字也被标记化了。

{
    "tokens": [
        {
            "token": "win_1",
            "start_offset": 0,
            "end_offset": 5,
            "type": "word",
            "position": 1
        },
        {
            "token": "win",
            "start_offset": 0,
            "end_offset": 3,
            "type": "word",
            "position": 1
        },
        {
            "token": "1",
            "start_offset": 4,
            "end_offset": 5,
            "type": "word",
            "position": 2
        }
    ]
}

我希望能够做的是搜索WIN并找回任何拥有WIN名字的主机。但我还需要能够搜索WIN_1并以其名称获取具有WIN_1的确切主机或任何主机。以下是一些测试数据。

{
    "ipaddress": "192.168.1.253",
    "hostname": "WIN_8_ENT_1"
}
{
    "ipaddress": "10.0.0.1",
    "hostname": "server1"
}
{
    "ipaddress": "172.20.10.36",
    "hostname": "ServA-1"
}

希望有人可以指出我正确的方向。可能是我的简单查询也不是正确的方法。我已经倾倒了ES文档,但它们并不是很好用的例子。

4 个答案:

答案 0 :(得分:3)

您可以更改分析以使用丢弃数字和分数下的模式分析器:

{
   "analysis": {
      "analyzer": {
          "word_only": {
              "type": "pattern",
              "pattern": "([^\p{L}]+)"
          }
       }
    }
}

使用analyze API:

curl -XGET 'localhost:9200/{yourIndex}/_analyze?analyzer=word_only&pretty=true' -d 'WIN_8_ENT_1'

返回:

"tokens" : [ {
    "token" : "win",
    "start_offset" : 0,
    "end_offset" : 3,
    "type" : "word",
    "position" : 1
}, {
    "token" : "ent",
    "start_offset" : 6,
    "end_offset" : 9,
    "type" : "word",
    "position" : 2
} ]

您的映射将变为:

{
    "event": {
        "properties": {
            "ipaddress": {
                 "type": "string"
             },
             "hostname": {
                 "type": "string",
                 "analyzer": "word_only",
                 "fields": {
                     "raw": {
                         "type": "string",
                         "index": "not_analyzed"
                     }
                 }
             }
         }
    }
}

您可以使用multi_match查询来获得所需的结果:

{
    "query": {
        "multi_match": {
            "fields": [
                "hostname",
                "hostname.raw"
            ],
            "query": "WIN_1"
       }
   }
}

答案 1 :(得分:1)

以下是我最终得到的分析器和查询:

{
    "mappings": {
        "event": {
            "properties": {
                "ipaddress": {
                    "type": "string"
                },
                "hostname": {
                    "type": "string",
                    "analyzer": "hostname_analyzer",
                    "fields": {
                        "raw": {
                            "type": "string",
                            "index": "not_analyzed"
                        }
                    }
                }
            }
        }
    },
    "settings": {
        "analysis": {
            "filter": {
                "hostname_filter": {
                    "type": "pattern_capture",
                    "preserve_original": 0,
                    "patterns": [
                        "(\\p{Ll}{3,})"
                    ]
                }
            },
            "analyzer": {
                "hostname_analyzer": {
                    "type": "custom",
                    "tokenizer": "whitespace",
                    "filter": [  "lowercase", "hostname_filter" ]
                }
            }
        }
    }
}

查询: 查找以:

开头的主机名
{
    "query": {
        "prefix": {
            "hostname.raw": "WIN_8"
        }
    }
}

查找包含以下内容的主机名:

{
    "query": {
        "multi_match": {
            "fields": [
                "hostname",
                "hostname.raw"
            ],
            "query": "WIN"
       }
   }
}

感谢Dan让我朝着正确的方向前进。

答案 2 :(得分:1)

当发布ES 1.4时,会有一个名为“keep types”的新过滤器,只有在字符串被标记化后才允许您保留某些类型。 (即仅保留单词,仅保留数字等)。

在这里查看: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-keep-types-tokenfilter.html#analysis-keep-types-tokenfilter

这可能是一种更方便的解决方案,可满足您未来的需求

答案 3 :(得分:0)

您希望在主机名字段上应用两种不同类型的搜索。一个用于完全匹配,一个用于通配符的变体(可能在您的特定情况下,前缀查询)。

在尝试使用多个不同的分析器实现所有类型的不同搜索之后,我发现添加另一个字段来表示您想要执行的每种类型的搜索有时更简单。您是否有理由不想添加以下字段:

{     “ipaddress”:“192.168.1.253”,     “hostname”:“WIN_8_ENT_1”     “系统”:“赢” }

否则,您可以考虑编写自己的自定义过滤器,它可以有效地完成同样的工作。您的过滤器将在您的主机名字段中读取并索引完全关键字和与您的词干模式匹配的子字符串(例如WIN_8_ENT_1中的WIN)。

我认为没有任何现有的分析仪/过滤器组合能够满足您的需求,假设我已正确理解您的要求。