【问题标题】:Elasticsearch custom analyzer with ngram and without word delimiter on hyphensElasticsearch 自定义分析器,带有 ngram,连字符上没有单词分隔符
【发布时间】:2017-04-16 03:19:13
【问题描述】:

我正在尝试索引包含连字符但不包含空格、句点或任何其他标点符号的字符串。我不想根据连字符拆分单词,而是希望连字符成为索引文本的一部分。

例如,我的 6 个文本字符串是:

  • 杂志播放
  • 马杂志
  • 在线杂志
  • 最佳杂志
  • 杂志之友
  • 杂志游戏

我希望能够在这些字符串中搜索包含“play”的文本以“magazine”开头的文本

我已经能够使用 ngram 使包含“play”的文本正常工作。但是,连字符会导致文本拆分,并且包括连字符后面的单词中出现“杂志”的结果。我只希望出现以“magazine”开头的字符串。

根据上面的示例,以“magazine”开头时应该只出现这 3 个:

  • 杂志播放
  • 马杂志
  • 杂志游戏

请帮助我的 ElasticSearch 索引示例:

DELETE /sample

PUT /sample
{
    "settings": {
        "index.number_of_shards":5,
        "index.number_of_replicas": 0,
        "analysis": {
            "filter": {
                "nGram_filter": {
                   "type": "nGram",
                   "min_gram": 2,
                   "max_gram": 20,
                   "token_chars": [
                      "letter",
                      "digit"
                   ]
                },
                "word_delimiter_filter": {
                    "type": "word_delimiter",
                    "preserve_original": true,
                    "catenate_all" : true
                }
             },
          "analyzer": {
            "ngram_index_analyzer": {
              "type" : "custom",
              "tokenizer": "lowercase",
              "filter" : ["nGram_filter", "word_delimiter_filter"]
            }
          }
        }
    }
}
PUT /sample/1/_create
{
    "name" : "magazineplayon"
}
PUT /sample/3/_create
{
    "name" : "magazineofhorses"
}
PUT /sample/4/_create
{
    "name" : "online-magazine"
}
PUT /sample/5/_create
{
    "name" : "best-magazine"
}
PUT /sample/6/_create
{
    "name" : "friend-of-magazines"
}
PUT /sample/7/_create
{
    "name" : "magazineplaygames"
}

GET /sample/_search
{
"query": {
        "wildcard": {
          "name": "*play*" 
        }
    }
}

GET /sample/_search
{
"query": {
        "wildcard": {
          "name": "magazine*" 
        }
    }
}

更新 1 我更新了所有创建语句以在示例之后使用 TEST:

PUT /sample/test/7/_create
{
    "name" : "magazinefairplay"
}

然后我运行以下命令以仅返回包含单词“play”的名称,而不是进行通配符搜索。这工作正常,只返回了两条记录。

POST /sample/test/_search
{
    "query": {
        "bool": {
            "minimum_should_match": 1,
            "should": [
                {"match": { "name.substrings": "play" }}
            ]
        }
    }
}

我运行以下命令只返回以“magazine”开头的名称。我的预期是“在线杂志”、“最佳杂志”和“杂志之友”不会出现。但是,包括这三个在内的所有七条记录都返回了。

POST /sample/test/_search
{
    "query": {
        "bool": {
            "minimum_should_match": 1,
            "should": [
                {"match": { "name.prefixes": "magazine" }}
            ]
        }
    }
}

有没有办法过滤掉使用连字符的前缀?

【问题讨论】:

  • 我尝试使用前缀命令作为搜索的一部分,而不是通配符,但这没有帮助。

    GET /sample/_search { "query": { "prefix" : { "name" : "magazine" } } }

标签: elasticsearch tokenize analysis analyzer


【解决方案1】:

您在正确的道路上,但是,您还需要添加另一个利用 edge-ngram token filter 的分析器,以使“开始于”约束起作用。您可以保留 ngram 来检查“包含”给定单词的字段,但您需要 edge-ngram 来检查字段是否“以”某个标记“开头”。

PUT /sample
{
  "settings": {
    "index.number_of_shards": 5,
    "index.number_of_replicas": 0,
    "analysis": {
      "filter": {
        "nGram_filter": {
          "type": "nGram",
          "min_gram": 2,
          "max_gram": 20,
          "token_chars": [
            "letter",
            "digit"
          ]
        },
        "edgenGram_filter": {
          "type": "edgeNGram",
          "min_gram": 2,
          "max_gram": 20
        }
      },
      "analyzer": {
        "ngram_index_analyzer": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": [
            "lowercase",
            "nGram_filter"
          ]
        },
        "edge_ngram_index_analyzer": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": [
            "lowercase",
            "edgenGram_filter"
          ]
        }
      }
    }
  },
  "mappings": {
    "test": {
      "properties": {
        "name": {
          "type": "string",
          "fields": {
            "prefixes": {
              "type": "string",
              "analyzer": "edge_ngram_index_analyzer",
              "search_analyzer": "standard"
            },
            "substrings": {
              "type": "string",
              "analyzer": "ngram_index_analyzer",
              "search_analyzer": "standard"
            }
          }
        }
      }
    }
  }
}

那么您的查询将变为(即搜索所有name 字段包含play 或以magazine 开头的文档)

POST /sample/test/_search
{
    "query": {
        "bool": {
            "minimum_should_match": 1,
            "should": [
                {"match": { "name.substrings": "play" }},
                {"match": { "name.prefixes": "magazine" }}
            ]
        }
    }
}

注意:不要使用wildcard 搜索子字符串,因为它会降低集群的性能(更多信息herehere

【讨论】:

  • 更新 1 我尝试了上面的建议,但我得到了所有 7 条记录。我在上面发布了我尝试使用的命令。
  • 很好,。我已经删除了导致问题的单词分隔符过滤器,我也更改了标记器。请重试
  • 太棒了,很高兴它有帮助!
猜你喜欢
  • 1970-01-01
  • 2015-05-15
  • 1970-01-01
  • 2017-03-21
  • 1970-01-01
  • 2012-03-05
  • 1970-01-01
  • 2010-09-18
  • 1970-01-01
相关资源
最近更新 更多