Elasticsearchカスタムトークナイザー

一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して13日目です

序文

canalを使用して最後のelasticsearchを継承し、配列フィールドを処理します。実際、最初の不注意により、運河構成ファイルでobjFieldフィールドの配列構成が有効になっておらず、配列として最初にマップされると予想していたフィールドが文字列フィールドに正常にマップされました。したがって、疑問が生じます。たとえば、elasticsearchに商品オブジェクトがあり、複数のラベルに対応できます。商品のドキュメントに関連付けられたラベルID、中国語のラベル、英語のラベルを保存する必要があります。何らかの理由で、配列として格納されるはずだったこれらのフィールドは、句読点(セミコロンなど)で連結された文字列に圧縮されました。

{
 "labels": "1;2;3",
 "labels_cn": "历史;中国;精品课",
 "labels_en": "history;china;class quality"
 }
{
  "label_cn_names": {
       "type": "text"
   },
  "label_en_names": {
       "type": "text"
   },
  "labels": {
       "type": "text"
   }
}
复制代码

上記はドキュメントストレージの一部です。1。ストレージは文字列です。2。フィールドタイプはテキストです。

検索時にテキストがセグメント化されます。たとえば、タグID、中国語タグ、英語タグで検索する必要があります。

31="31番目のラベルIDにバインドされたオブジェクトを取得します

China="バインドされた中国語タグは中国のオブジェクトです

中国=>バインドされた英語タグを取得することは中国の目的です。

たとえば、一致するクエリがあいまいな場合、タグが誤ってヒットする傾向がある場合、英語でbagを検索すると、タグ「shcoolandbag」も返されます。中国語ではI国を検索すると、タグ「中国」も返されます。テキストタイプは検索中に分析およびセグメント化され、デフォルトの標準トークナイザーまたはikトークナイザーは単語セグメント化後に誤動作するためです。この分割文字列では、「配列」内の個々の値を正確に一致させる必要もあります。では、単語のセグメンテーションから始める必要がありますか?たとえば、区切り文字によれば、各単語のセグメンテーションは配列の各値であるため、検索中にアナライザーによって単語のセグメンテーションが実行された場合でも、各セグメンテーションの単語の値は完全になります。一致しました。

カスタム分詞

まず、elasticsearchのアナライザーが3つの部分で構成されていることを簡単に説明しましょう:1、0以上の文字フィルター2、トークナイザー3、0以上のトークンフィルター私たちがしなければならないのは、トークナイザーを作成することだけです。パターントークナイザーの場合。パターンセグメンテーションとは、正規表現によるテキストの分離を指します。

PUT my-index-000001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "pattern",
          "pattern": ","
        }
      }
    }
  }
}

POST my-index-000001/_analyze
{
  "analyzer": "my_analyzer",
  "text": "comma,separated,values"
}
复制代码

例如这是一个逗号的分词器。所有文本会按照逗号分隔。我们给我们的索引创建一个分号的分词器。 下面来看下比较,首先是没有用自定义分词器的

{
    "query":{
        "match":{
            "labels_cn": "课"
        }
    }
}
--------------------
 "hits": [
            {
                "_index": "book",
                "_type": "_doc",
                "_id": "HjPUJ4ABRHGvpe9lz-Be",
                "_score": 0.2876821,
                "_source": {
                    "book_name": "畅销书",
                    "labels": "1;2;3",
                    "labels_cn": "历史;中国;精品课",
                    "labels_en": "history;china;class quality"
                }
            }
        ]
复制代码

可以看到有结果返回,可以理论上只有搜索精品课才能返回。这是由于labels_cn被分词了,例如你是用了ik,那么很有可能分词为精品、课。所以就会被误匹配。 下面我们增加自定义分词器,然后再进行同样的查询

{
    "query":{
        "match":{
            "labels_cn": "课"
        }
    }
}
------------
"hits": {
        "total": {
            "value": 0,
            "relation": "eq"
        },
        "max_score": null,
        "hits": []
    }
复制代码

很神奇,没有返回。为了方便理解,我们测试下分词器的作用,使用_analyze API

{
    "analyzer": "semicolon_analyzer",
    "text": "历史;中国;精品课"
}
{
    "tokens": [
        {
            "token": "历史",
            "start_offset": 0,
            "end_offset": 2,
            "type": "word",
            "position": 0
        },
        {
            "token": "中国",
            "start_offset": 3,
            "end_offset": 5,
            "type": "word",
            "position": 1
        },
        {
            "token": "精品课",
            "start_offset": 6,
            "end_offset": 9,
            "type": "word",
            "position": 2
        }
    ]
}
复制代码

看到文本只会按照分号进行分词。所以也只可能被完整的标签值匹配。下面输入完整的标签来搜索

{
    "query":{
        "match":{
            "labels_cn": "精品课"
        }
    }
}
----------
 "hits": [
            {
                "_index": "book1",
                "_type": "_doc",
                "_id": "HzPcJ4ABRHGvpe9lHeCW",
                "_score": 0.18232156,
                "_source": {
                    "book_name": "畅销书",
                    "labels": "1;2;3",
                    "labels_cn": "历史;中国;精品课",
                    "labels_en": "history;china;class quality"
                }
            }
            ]
复制代码

可以看到符合我们的预期了。

おすすめ

転載: juejin.im/post/7086662432231260197