边缘 n 元语法分词器

编辑

edge_ngram 分词器首先在遇到指定字符列表中的任何一个字符时将文本分解成单词,然后发出每个单词的 N 元语法,其中 N 元语法的起始位置锚定在单词的开头。

边缘 N 元语法对于边输入边搜索查询非常有用。

当您需要对具有广为人知的顺序的文本进行边输入边搜索,例如电影或歌曲标题时,完成建议器比边缘 N 元语法更有效率。 当尝试自动完成可以以任何顺序出现的单词时,边缘 N 元语法具有优势。

示例输出

编辑

使用默认设置,edge_ngram 分词器将初始文本视为单个词元,并生成最小长度为 1,最大长度为 2 的 N 元语法。

resp = client.indices.analyze(
    tokenizer="edge_ngram",
    text="Quick Fox",
)
print(resp)
response = client.indices.analyze(
  body: {
    tokenizer: 'edge_ngram',
    text: 'Quick Fox'
  }
)
puts response
const response = await client.indices.analyze({
  tokenizer: "edge_ngram",
  text: "Quick Fox",
});
console.log(response);
POST _analyze
{
  "tokenizer": "edge_ngram",
  "text": "Quick Fox"
}

上面的句子将产生以下词项

[ Q, Qu ]

这些默认的语法长度几乎完全无用。您需要在使用 edge_ngram 之前对其进行配置。

配置

编辑

edge_ngram 分词器接受以下参数

min_gram
语法中字符的最小长度。默认为 1
max_gram

语法中字符的最大长度。默认为 2

请参阅 max_gram 参数的限制

token_chars

应该包含在词元中的字符类。 Elasticsearch 将在不属于指定类别的字符上进行拆分。 默认为 [](保留所有字符)。

字符类可以是以下任何一种

  • letter —  例如 abï
  • digit —  例如 37
  • whitespace —  例如 " ""\n"
  • punctuation — 例如 !"
  • symbol —  例如 $
  • custom —  使用 custom_token_chars 设置的自定义字符。
custom_token_chars
应被视为词元一部分的自定义字符。例如,将其设置为 +-_ 将使分词器将加号、减号和下划线符号视为词元的一部分。

max_gram 参数的限制

编辑

edge_ngram 分词器的 max_gram 值限制了词元的字符长度。当 edge_ngram 分词器与索引分析器一起使用时,这意味着长度大于 max_gram 长度的搜索词可能与任何索引词都不匹配。

例如,如果 max_gram3,则搜索 apple 将不会匹配索引词 app

为了解决这个问题,您可以使用 truncate 词元过滤器与搜索分析器一起使用,将搜索词缩短到 max_gram 字符长度。但是,这可能会返回不相关的结果。

例如,如果 max_gram3,并且搜索词被截断为三个字符,则搜索词 apple 将缩短为 app。这意味着对 apple 的搜索会返回任何与 app 匹配的索引词,例如 applyapproximateapple

我们建议测试这两种方法,看看哪种方法最适合您的用例和所需的搜索体验。

示例配置

编辑

在此示例中,我们将 edge_ngram 分词器配置为将字母和数字视为词元,并生成最小长度为 2,最大长度为 10 的语法。

resp = client.indices.create(
    index="my-index-000001",
    settings={
        "analysis": {
            "analyzer": {
                "my_analyzer": {
                    "tokenizer": "my_tokenizer"
                }
            },
            "tokenizer": {
                "my_tokenizer": {
                    "type": "edge_ngram",
                    "min_gram": 2,
                    "max_gram": 10,
                    "token_chars": [
                        "letter",
                        "digit"
                    ]
                }
            }
        }
    },
)
print(resp)

resp1 = client.indices.analyze(
    index="my-index-000001",
    analyzer="my_analyzer",
    text="2 Quick Foxes.",
)
print(resp1)
response = client.indices.create(
  index: 'my-index-000001',
  body: {
    settings: {
      analysis: {
        analyzer: {
          my_analyzer: {
            tokenizer: 'my_tokenizer'
          }
        },
        tokenizer: {
          my_tokenizer: {
            type: 'edge_ngram',
            min_gram: 2,
            max_gram: 10,
            token_chars: [
              'letter',
              'digit'
            ]
          }
        }
      }
    }
  }
)
puts response

response = client.indices.analyze(
  index: 'my-index-000001',
  body: {
    analyzer: 'my_analyzer',
    text: '2 Quick Foxes.'
  }
)
puts response
const response = await client.indices.create({
  index: "my-index-000001",
  settings: {
    analysis: {
      analyzer: {
        my_analyzer: {
          tokenizer: "my_tokenizer",
        },
      },
      tokenizer: {
        my_tokenizer: {
          type: "edge_ngram",
          min_gram: 2,
          max_gram: 10,
          token_chars: ["letter", "digit"],
        },
      },
    },
  },
});
console.log(response);

const response1 = await client.indices.analyze({
  index: "my-index-000001",
  analyzer: "my_analyzer",
  text: "2 Quick Foxes.",
});
console.log(response1);
PUT my-index-000001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 10,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      }
    }
  }
}

POST my-index-000001/_analyze
{
  "analyzer": "my_analyzer",
  "text": "2 Quick Foxes."
}

上面的示例产生以下词项

[ Qu, Qui, Quic, Quick, Fo, Fox, Foxe, Foxes ]

通常,我们建议在索引时和搜索时使用相同的 analyzer。对于 edge_ngram 分词器,建议有所不同。仅在索引时使用 edge_ngram 分词器才有意义,以确保索引中可以使用部分单词进行匹配。在搜索时,只需搜索用户键入的词项,例如:Quick Fo

以下是如何为边输入边搜索设置字段的示例。

请注意,索引分析器的 max_gram 值为 10,这会将索引词限制为 10 个字符。搜索词不会被截断,这意味着长度超过 10 个字符的搜索词可能与任何索引词都不匹配。

resp = client.indices.create(
    index="my-index-000001",
    settings={
        "analysis": {
            "analyzer": {
                "autocomplete": {
                    "tokenizer": "autocomplete",
                    "filter": [
                        "lowercase"
                    ]
                },
                "autocomplete_search": {
                    "tokenizer": "lowercase"
                }
            },
            "tokenizer": {
                "autocomplete": {
                    "type": "edge_ngram",
                    "min_gram": 2,
                    "max_gram": 10,
                    "token_chars": [
                        "letter"
                    ]
                }
            }
        }
    },
    mappings={
        "properties": {
            "title": {
                "type": "text",
                "analyzer": "autocomplete",
                "search_analyzer": "autocomplete_search"
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="my-index-000001",
    id="1",
    document={
        "title": "Quick Foxes"
    },
)
print(resp1)

resp2 = client.indices.refresh(
    index="my-index-000001",
)
print(resp2)

resp3 = client.search(
    index="my-index-000001",
    query={
        "match": {
            "title": {
                "query": "Quick Fo",
                "operator": "and"
            }
        }
    },
)
print(resp3)
response = client.indices.create(
  index: 'my-index-000001',
  body: {
    settings: {
      analysis: {
        analyzer: {
          autocomplete: {
            tokenizer: 'autocomplete',
            filter: [
              'lowercase'
            ]
          },
          autocomplete_search: {
            tokenizer: 'lowercase'
          }
        },
        tokenizer: {
          autocomplete: {
            type: 'edge_ngram',
            min_gram: 2,
            max_gram: 10,
            token_chars: [
              'letter'
            ]
          }
        }
      }
    },
    mappings: {
      properties: {
        title: {
          type: 'text',
          analyzer: 'autocomplete',
          search_analyzer: 'autocomplete_search'
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'my-index-000001',
  id: 1,
  body: {
    title: 'Quick Foxes'
  }
)
puts response

response = client.indices.refresh(
  index: 'my-index-000001'
)
puts response

response = client.search(
  index: 'my-index-000001',
  body: {
    query: {
      match: {
        title: {
          query: 'Quick Fo',
          operator: 'and'
        }
      }
    }
  }
)
puts response
const response = await client.indices.create({
  index: "my-index-000001",
  settings: {
    analysis: {
      analyzer: {
        autocomplete: {
          tokenizer: "autocomplete",
          filter: ["lowercase"],
        },
        autocomplete_search: {
          tokenizer: "lowercase",
        },
      },
      tokenizer: {
        autocomplete: {
          type: "edge_ngram",
          min_gram: 2,
          max_gram: 10,
          token_chars: ["letter"],
        },
      },
    },
  },
  mappings: {
    properties: {
      title: {
        type: "text",
        analyzer: "autocomplete",
        search_analyzer: "autocomplete_search",
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "my-index-000001",
  id: 1,
  document: {
    title: "Quick Foxes",
  },
});
console.log(response1);

const response2 = await client.indices.refresh({
  index: "my-index-000001",
});
console.log(response2);

const response3 = await client.search({
  index: "my-index-000001",
  query: {
    match: {
      title: {
        query: "Quick Fo",
        operator: "and",
      },
    },
  },
});
console.log(response3);
PUT my-index-000001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "autocomplete": {
          "tokenizer": "autocomplete",
          "filter": [
            "lowercase"
          ]
        },
        "autocomplete_search": {
          "tokenizer": "lowercase"
        }
      },
      "tokenizer": {
        "autocomplete": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 10,
          "token_chars": [
            "letter"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "autocomplete",
        "search_analyzer": "autocomplete_search"
      }
    }
  }
}

PUT my-index-000001/_doc/1
{
  "title": "Quick Foxes" 
}

POST my-index-000001/_refresh

GET my-index-000001/_search
{
  "query": {
    "match": {
      "title": {
        "query": "Quick Fo", 
        "operator": "and"
      }
    }
  }
}

autocomplete 分析器为词项 [qu, qui, quic, quick, fo, fox, foxe, foxes]建立索引。

autocomplete_search 分析器搜索词项 [quick, fo],这两个词项都出现在索引中。