在Elasticsearch

时间:2017-07-10 22:31:21

标签: elasticsearch

我使用自定义分析器删除某组停用词。然后,我使用包含一些停用词的文本进行词组匹配查询。我希望停用词从查询中过滤掉,但它们不会(并且任何不包含停用词的文档都会被排除在结果之外)。

以下是我尝试做的简单示例:

#!/bin/bash

export ELASTICSEARCH_ENDPOINT="http://localhost:9200"

# Create index, with a custom analyzer to filter out the word 'foo'
curl -XPUT "$ELASTICSEARCH_ENDPOINT/play" -d '{
    "settings": {
        "analysis": {
            "analyzer": {
                "fooAnalyzer": {
                    "type": "custom",
                    "tokenizer": "letter",
                    "filter": [
                        "fooFilter"
                    ]
                }
            },
            "filter": {
                "fooFilter": {
                    "type": "stop",
                    "stopwords": [
                        "foo"
                    ]
                }
            }
        }
    },
    "mappings": {
        "myDocument": {
            "properties": {
                "myMessage": {
                    "analyzer": "fooAnalyzer",
                    "type": "string"
                }
            }
        }
    }
}'

# Add sample document
curl -XPOST "$ELASTICSEARCH_ENDPOINT/_bulk?refresh=true" -d '
{"index":{"_index":"play","_type":"myDocument"}}
{"myMessage":"bar baz"}
'

如果我在查询中间使用过滤后的停用词对此索引执行phrase_match搜索,我希望它匹配(因为' foo'应该被我们的分析器过滤掉)。

curl -XPOST "$ELASTICSEARCH_ENDPOINT/_search?pretty" -d '
{
    "query": {
        "match": {
            "myMessage": {
                "type": "phrase",
                "query": "bar foo baz"
            }
        }
    }
}
'

然而,我没有结果。

有没有办法指示Elasticsearch在执行搜索之前对查询字符串进行标记化和过滤?

编辑1:现在我更加困惑。我之前看到,如果我的查询在查询文本中间包含停用词,那么词组匹配就不起作用了。现在,此外,如果文档在查询文本的中间包含停用词,我发现短语查询不起作用。这是一个最小的例子,仍然使用上面的映射。

POST play/myDocument
{
  "myMessage": "fib foo bar"  <---- remember that 'foo' is a stopword and is filtered out of analysis
}

GET play/_search
{
    "query": {
        "match": {
            "myMessage": {
                "type": "phrase",
                "query": "fib bar"
            }
        }
    }
}

此查询不匹配。我对此感到非常惊讶!我希望foo stopword被过滤掉并被忽略。

有关我为什么会这样做的示例,请参阅此查询:

POST play/myDocument
{
  "myMessage": "fib 123 bar"
}

GET play/_search
{
    "query": {
        "match": {
            "myMessage": {
                "type": "phrase",
                "query": "fib bar"
            }
        }
    }
}

这匹配,因为&#39; 123&#39;被我的字母&#39;过滤掉了标记生成器。似乎短语匹配完全忽略了禁用词过滤,并且好像这些标记一直在分析的字段中(即使它们不会出现在_analyze的标记列表中)。

我目前最好的解决方法:

  • 使用我的自定义分析器针对文档的文本字符串调用_analyze端点。这将从原始文本字符串返回标记,但为我删除讨厌的停用词
  • 将我的文字的一个版本仅使用令牌保存到&#34;已过滤的&#34;文件中的字段

稍后,在查询时:

  • 使用我的自定义分析器对我的查询字符串调用_analyze端点以获取令牌
  • 使用已过滤的令牌字符串对文档的新&#34;过滤&#34;使我的短语匹配查询字段

2 个答案:

答案 0 :(得分:0)

应该有效的解决方法:

  • 使用我的自定义分析器针对我的查询字符串调用_analyze端点。这将从原始查询字符串返回标记,但为我删除讨厌的停用词
  • 使用过滤的令牌使我的短语匹配查询

但是,对于我的每个查询,这显然需要两次调用Elasticsearch。如果可能的话,我想找到更好的解决方案。

答案 1 :(得分:0)

事实证明,如果您想使用词组匹配,则令牌过滤器为时已晚,无法删除不需要的词。到那时,&#39;位置&#39;您的重要令牌字段因过滤令牌的存在而受到污染,并且短语匹配拒绝工作。

答案 - 在我们到达令牌过滤器级别之前进行过滤。我创建了一个char_filter来删除我们不需要的术语和短语匹配开始正常工作!

PUT play 
{
    "settings": {
        "analysis": {
            "analyzer": {
                "fooAnalyzer": {
                    "type": "custom",
                    "tokenizer": "letter",
                    "char_filter": [
                        "fooFilter"
                    ]
                }
            },
            "char_filter": {
                "fooFilter": {
                    "type": "pattern_replace",
                    "pattern": "(foo)",
                    "replacement": ""
                }
            }
        }
    },
    "mappings": {
        "myDocument": {
            "properties": {
                "myMessage": {
                    "analyzer": "fooAnalyzer",
                    "type": "string"
                }
            }
        }
    }
}

查询:

POST play/myDocument
{
  "myMessage": "fib bar"
}

GET play/_search
{
    "query": {
        "match": {
            "myMessage": {
                "type": "phrase",
                "query": "fib foo bar"
            }
        }
    }
}

POST play/myDocument
{
  "myMessage": "fib foo bar"
}

GET play/_search
{
    "query": {
        "match": {
            "myMessage": {
                "type": "phrase",
                "query": "fib bar"
            }
        }
    }
}

现在都有效!