copy_to

编辑

copy_to 参数允许您将多个字段的值复制到一个组字段中,然后可以将其作为单个字段进行查询。

如果您经常搜索多个字段,您可以使用 copy_to 来搜索较少的字段,从而提高搜索速度。请参阅尽可能搜索较少的字段

例如,可以将 first_namelast_name 字段复制到 full_name 字段,如下所示

resp = client.indices.create(
    index="my-index-000001",
    mappings={
        "properties": {
            "first_name": {
                "type": "text",
                "copy_to": "full_name"
            },
            "last_name": {
                "type": "text",
                "copy_to": "full_name"
            },
            "full_name": {
                "type": "text"
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="my-index-000001",
    id="1",
    document={
        "first_name": "John",
        "last_name": "Smith"
    },
)
print(resp1)

resp2 = client.search(
    index="my-index-000001",
    query={
        "match": {
            "full_name": {
                "query": "John Smith",
                "operator": "and"
            }
        }
    },
)
print(resp2)
response = client.indices.create(
  index: 'my-index-000001',
  body: {
    mappings: {
      properties: {
        first_name: {
          type: 'text',
          copy_to: 'full_name'
        },
        last_name: {
          type: 'text',
          copy_to: 'full_name'
        },
        full_name: {
          type: 'text'
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'my-index-000001',
  id: 1,
  body: {
    first_name: 'John',
    last_name: 'Smith'
  }
)
puts response

response = client.search(
  index: 'my-index-000001',
  body: {
    query: {
      match: {
        full_name: {
          query: 'John Smith',
          operator: 'and'
        }
      }
    }
  }
)
puts response
const response = await client.indices.create({
  index: "my-index-000001",
  mappings: {
    properties: {
      first_name: {
        type: "text",
        copy_to: "full_name",
      },
      last_name: {
        type: "text",
        copy_to: "full_name",
      },
      full_name: {
        type: "text",
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "my-index-000001",
  id: 1,
  document: {
    first_name: "John",
    last_name: "Smith",
  },
});
console.log(response1);

const response2 = await client.search({
  index: "my-index-000001",
  query: {
    match: {
      full_name: {
        query: "John Smith",
        operator: "and",
      },
    },
  },
});
console.log(response2);
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "first_name": {
        "type": "text",
        "copy_to": "full_name" 
      },
      "last_name": {
        "type": "text",
        "copy_to": "full_name" 
      },
      "full_name": {
        "type": "text"
      }
    }
  }
}

PUT my-index-000001/_doc/1
{
  "first_name": "John",
  "last_name": "Smith"
}

GET my-index-000001/_search
{
  "query": {
    "match": {
      "full_name": { 
        "query": "John Smith",
        "operator": "and"
      }
    }
  }
}

first_namelast_name 字段的值将被复制到 full_name 字段。

仍然可以分别查询 first_namelast_name 字段以获取名字和姓氏,但可以查询 full_name 字段以获取名字和姓氏。

一些重点:

  • 复制的是字段,而不是术语(术语是分析过程的结果)。
  • 原始的 _source 字段不会被修改以显示复制的值。
  • 可以将同一个值复制到多个字段,使用 "copy_to": [ "field_1", "field_2" ]
  • 您不能使用中间字段递归复制。以下配置不会将数据从 field_1 复制到 field_3

    resp = client.indices.create(
        index="bad_example_index",
        mappings={
            "properties": {
                "field_1": {
                    "type": "text",
                    "copy_to": "field_2"
                },
                "field_2": {
                    "type": "text",
                    "copy_to": "field_3"
                },
                "field_3": {
                    "type": "text"
                }
            }
        },
    )
    print(resp)
    const response = await client.indices.create({
      index: "bad_example_index",
      mappings: {
        properties: {
          field_1: {
            type: "text",
            copy_to: "field_2",
          },
          field_2: {
            type: "text",
            copy_to: "field_3",
          },
          field_3: {
            type: "text",
          },
        },
      },
    });
    console.log(response);
    PUT bad_example_index
    {
      "mappings": {
        "properties": {
          "field_1": {
            "type": "text",
            "copy_to": "field_2"
          },
          "field_2": {
            "type": "text",
            "copy_to": "field_3"
          },
          "field_3": {
            "type": "text"
          }
        }
      }
    }

    相反,从源字段复制到多个字段

    resp = client.indices.create(
        index="good_example_index",
        mappings={
            "properties": {
                "field_1": {
                    "type": "text",
                    "copy_to": [
                        "field_2",
                        "field_3"
                    ]
                },
                "field_2": {
                    "type": "text"
                },
                "field_3": {
                    "type": "text"
                }
            }
        },
    )
    print(resp)
    const response = await client.indices.create({
      index: "good_example_index",
      mappings: {
        properties: {
          field_1: {
            type: "text",
            copy_to: ["field_2", "field_3"],
          },
          field_2: {
            type: "text",
          },
          field_3: {
            type: "text",
          },
        },
      },
    });
    console.log(response);
    PUT good_example_index
    {
      "mappings": {
        "properties": {
          "field_1": {
            "type": "text",
            "copy_to": ["field_2", "field_3"]
          },
          "field_2": {
            "type": "text"
          },
          "field_3": {
            "type": "text"
          }
        }
      }
    }

copy_to 不支持值采用对象形式的字段类型,例如 date_range

动态映射

编辑

copy_to 与动态映射一起使用时,请考虑以下几点:

  • 如果目标字段在索引映射中不存在,则应用通常的动态映射行为。默认情况下,当 dynamic 设置为 true 时,一个不存在的目标字段将被动态添加到索引映射中。
  • 如果 dynamic 设置为 false,则目标字段不会被添加到索引映射中,并且该值不会被复制。
  • 如果 dynamic 设置为 strict,则复制到不存在的字段将导致错误。

    • 如果目标字段是嵌套的,则 copy_to 字段必须指定嵌套字段的完整路径。省略完整路径将导致 strict_dynamic_mapping_exception。使用 "copy_to": ["parent_field.child_field"] 来正确定位嵌套字段。

      例如:

      resp = client.indices.create(
          index="test_index",
          mappings={
              "dynamic": "strict",
              "properties": {
                  "description": {
                      "properties": {
                          "notes": {
                              "type": "text",
                              "copy_to": [
                                  "description.notes_raw"
                              ],
                              "analyzer": "standard",
                              "search_analyzer": "standard"
                          },
                          "notes_raw": {
                              "type": "keyword"
                          }
                      }
                  }
              }
          },
      )
      print(resp)
      const response = await client.indices.create({
        index: "test_index",
        mappings: {
          dynamic: "strict",
          properties: {
            description: {
              properties: {
                notes: {
                  type: "text",
                  copy_to: ["description.notes_raw"],
                  analyzer: "standard",
                  search_analyzer: "standard",
                },
                notes_raw: {
                  type: "keyword",
                },
              },
            },
          },
        },
      });
      console.log(response);
      PUT /test_index
      {
        "mappings": {
          "dynamic": "strict",
          "properties": {
            "description": {
              "properties": {
                "notes": {
                  "type": "text",
                  "copy_to": [ "description.notes_raw"], 
                  "analyzer": "standard",
                  "search_analyzer": "standard"
                },
                "notes_raw": {
                  "type": "keyword"
                }
              }
            }
          }
        }
      }

notes 字段被复制到 notes_raw 字段。仅定位 notes_raw 而不是 description.notes_raw 会导致 strict_dynamic_mapping_exception

在此示例中,notes_raw 未在映射的根目录中定义,而是在 description 字段下定义。如果没有完全限定的路径,Elasticsearch 会将 copy_to 目标解释为根级别的字段,而不是 description 下的嵌套字段。