インデックス追加フィールドと配列フィールドの同期と検索を実現するための運河を使用したElasticsearch

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

序文

以前に開発されたサービスは半年間オンラインであり、elasticsearchの検索も通常使用されています。最近、パーティAは多くの機能アップグレードを追加しました。製品のドキュメントを見てみましたが、良くありません。たくさんのフィールドを追加する必要があるように感じます。フィールドなどを追加する前に、不慣れなため、elasticsearchとcanalの両方がインデックスを削除してから、完全な更新コマンドを使用してmysqlからのデータを同期します。

Elasticsearchのドキュメントを注意深く読んだ後、フィールドを追加するだけで、APIを介してそれを実現できることがわかりました。

既存のインデックスにフィールドを追加

まず、ドキュメントから、elasticsearchでは、インデックスを再構築しない限り、フィールドタイプを直接変更したり、フィールドを直接削除したりすることはできないことを理解してください。ただし、ドキュメントデータベースの利点であるインデックスのフィールドを増やすことはサポートされています。フィールドを増やすことは非常に自由であり、テーブル内であっても、異なるレコードのフィールドは異なる場合があります。

Elasticsearchを使用すると、インデックスを作成するときにフィールドを宣言したり、既存のインデックスにフィールドを追加したりできます。たとえば、すでにインデックスがあり、その中にデータがある場合、_mappingapiを使用してこの機能を実現できます

curl --location --request PUT 'http://127.0.0.1:9200/test/_mapping' \
--header 'Authorization: Basic ZWxhc3RpYzplbGFzdGlj' \
--header 'Content-Type: application/json' \
--data-raw '{
    "properties": {
        "visible": {
            "type": "short"
        },
        "post_type": {
            "type": "short"
        },
        "post_status": {
            "type": "short"
        },
        "check_state": {
            "type": "short"
        },
        "gmt_checked": {
            "type": "keyword"
        },
        "official": {
            "type": "boolean"
        },
        "labels": {
            "type": "text"
        }
    }
}'
复制代码

プロパティで、追加するフィールドの名前とタイプを宣言します。

Elasticsearch配列フィールド

msysqlでは、配列型の場合、通常2つの設計があります。1つはこの配列フィールドを任意の区切り文字でつなぎ合わせて1つのフィールドに格納する方法、もう1つは1対多の関係を使用する方法です。2つのテーブルを別々に作成します。配列内の値を単一のフィールドに分散し、関連付けに別のフィールドを使用するテーブルを実装して、2つのテーブルがフィールドの配列を実装できるようにします。

但是在elasticsearch中并不是这样,首先文档存储非常自由,一个文档中存储的字段非常的自由。elasticsearch中并没有arrays的字段类型,任意一个字段都可以拥有0个或多个值,换句话说,如果你这个字段拥有了多个值,那么你就是数组类型,这里有一个要求就是这个字段中多个值的类型必须相同不能混合,比如[1,'abc']这种数字和字符串混合的就不行,不被elasticsearch所支持。

elasticsearch对于数组字段的搜索是这样的

PUT my-index-000001/_doc/1
{
  "message": "some arrays in this document...",
  "tags":  [ "elasticsearch", "wow" ], 
  "lists": [ 
    {
      "name": "prog_list",
      "description": "programming list"
    },
    {
      "name": "cool_list",
      "description": "cool stuff list"
    }
  ]
}

GET my-index-000001/_search
{
  "query": {
    "match": {
      "tags": "elasticsearch" 
    }
  }
}
复制代码

这里可以把tags包含elasticsearch的给筛选出来,应该是数组类型,会按照每个元素来进行分组,所以可以和搜索普通字段一样搜索数组。

canal 同步数组字段

我们当前使用的架构是mysql 通过canal将数据同步到elasticsearch中,鉴于elasticsearch文档中字段类型的灵活和多样性,不可避免的我们会同步到数组字段或者对象字段。那么如何去实现这一个功能呢?假设我们有一个商品的实体,它有个标签的属性,这个属性是允许有多个值的。我们之前了解,canal是通过一个sql查询把需要同步的数据查询出来,投影出自己需要的字段,然后对应同步到elasticsearch中。对于复杂字段,给出了这样的解决方案

image.png

在上面给出了如果你是希望你的sql中有些查询出来的字段要被映射成一个数组字段的话,那首先第一步开启和sql属性同级的objFields。这个字段主要是配置数组和json对象字段的。如果我们需要的是数组那么按照这样的格式配置 字段名: arrays:分隔符号 也就是我们必须在sql中查询返回结果中要带上这个分隔符号。 mysql中提供了一个聚合的拼接函数group_concat。这个函数的作用是将一系列非null的值串联起来成一个字符串。默认是通过,拼接,我们可以显式的指定拼接的符号,比如分号,回到我们的假设中,商品对应多个标签。我们可以构建一个查询 select product_id,group_concat(label order by label_id asec separator ';') as labels from product_labels group by product_id; 这样就可以把product关联的label通过先通过group by聚合起来,然后通过group_concat拼接。这里需要注意这种拼接函数默认字符拼接后最大长度1024,可以通过修改mysql全局参数group_concat_max_len来扩大。 我们修改canal的yml文件,重启canal,然后测试一下我们的同步

image.png

同步后会生成数组类型的字段。 也就是canal是能够支持我们把mysql中的一对多字段以数组的形式同步到elasticsearch中的。

おすすめ

転載: juejin.im/post/7086382152744435743