2024-03-13
原文作者:吴声子夜歌 原文地址: https://blog.csdn.net/cold___play/article/details/133841820

Term向量

词项向量(term vector)是有elasticsearch在index document的时候产生,其包含对document解析过程中产生的分词的一些信息,例如分词在字段值中的位置、开始和结束的字符位置、分词的元数据payloads等;

term vector是单独进行存储的,会额外多占用一杯的空间,所以elasticsearch默认情况下禁用词项向量,如果要启用,我们需要在字段的mapping中使用term_vector进行设置;

1、term_vector的配置选项

配置选项 描述
no 不启用termvector,默认值
yes 启用termvector,但是仅记录分词
with_positions 启用termvector,记录分词及分词在字符串中的位置
with_offsets 启用termvector,记录分词在字符串中的起始字符位置
with_positions_offsets 启用termvector,记录分词在字符串中的位置及起始的字符位置
with_positions_payloads 启用termvector,记录分词在字符串中的位置及payloads
with_positions_offsets_payloads 启用termvector,记录分词在字符串中的位置、起始字符位置及payloads
    PUT /twitter
    { "mappings": {
        "properties": {
          "text": {
            "type": "text",
            "term_vector": "with_positions_offsets_payloads",
            "store" : true,
            "analyzer" : "fulltext_analyzer"
           },
           "fullname": {
            "type": "text",
            "term_vector": "with_positions_offsets_payloads",
            "analyzer" : "fulltext_analyzer"
          }
        }
      },
      "settings" : {
        "index" : {
          "number_of_shards" : 1,
          "number_of_replicas" : 0
        },
        "analysis": {
          "analyzer": {
            "fulltext_analyzer": {
              "type": "custom",
              "tokenizer": "whitespace",
              "filter": [
                "lowercase",
                "type_as_payload"
              ]
            }
          }
        }
      }
    }

将以下两个document发送到elasticsearch进行index:

    PUT /twitter/_doc/1
    {
      "fullname" : "John Doe",
      "text" : "twitter test test test "
    }
    
    PUT /twitter/_doc/2?refresh=wait_for
    {
      "fullname" : "Jane Doe",
      "text" : "Another twitter test ..."
    }

2、查看term vector的数据结构

term vector主要由term information、term statistics、field statistics构成,其中term information又分成了positions、offsets、payloads三个选项,我们可以通过请求的body的参数分别控制返回的信息;

    //语法:
    GET /<index>/_termvectors/<_id>

示例:

    GET /twitter/_termvectors/1
    {
      "fields" : ["text"],
      "offsets" : true,
      "payloads" : true,
      "positions" : true,
      "term_statistics" : true,
      "field_statistics" : true
    }
    //返回
    {
      "_index" : "twitter",
      "_type" : "_doc",
      "_id" : "1",
      "_version" : 1,
      "found" : true,
      "took" : 0,
      "term_vectors" : {
        "text" : {
          "field_statistics" : {
            "sum_doc_freq" : 6,
            "doc_count" : 2,
            "sum_ttf" : 8
          },
          "terms" : {
            "test" : {
              "doc_freq" : 2,
              "ttf" : 4,
              "term_freq" : 3,
              "tokens" : [
                {
                  "position" : 1,
                  "start_offset" : 8,
                  "end_offset" : 12,
                  "payload" : "d29yZA=="
                },
                {
                  "position" : 2,
                  "start_offset" : 13,
                  "end_offset" : 17,
                  "payload" : "d29yZA=="
                },
                {
                  "position" : 3,
                  "start_offset" : 18,
                  "end_offset" : 22,
                  "payload" : "d29yZA=="
                }
              ]
            },
            "twitter" : {
              "doc_freq" : 2,
              "ttf" : 2,
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 0,
                  "start_offset" : 0,
                  "end_offset" : 7,
                  "payload" : "d29yZA=="
                }
              ]
            }
          }
        }
      }
    }

3、返回值信息

可以请求三种类型的值:Term信息、Term统计信息和字段统计 信息。默认情况下,返回所有字段的所有Term信息和字段统计信息, 但不返回Term统计信息。

基于以下两点term statistics和field statistics并不是准确的;

  • 删除的文档不会计算在内;
  • 只计算请求文档所在的分片的数据;

3.1、Term信息

  • term_freq :Term的频率(在对应字段中),这部分信息是始终返回的。
  • position :Term的位置,需要设置positions:true。
  • start_offset、end_offset :Term开始和结束的偏移量,需要设置offsets:true。
  • payload :分词的元数据,可以看到每个分词的payload都是d29yZA==,从这里可以到elasticsearch默认值为 word;

Term信息在Elasticsearch中的具体存储格式如图所示:

202403132037382921.png

如果请求的信息没有存储在索引中,可能的话,它将被动态计算。此外,还可以为索引中不存在但由用户提供的文档计算Term向量。

开始和结束偏移量假定使用了UTF-16编码。如果要使用这些偏 移量来获取原始文本,应确保子字符串也使用UTF-16编码。

3.2、Term统计信息

需要将term_statistics设置为true,其默认值为false。Term统 计信息包括如下两方面的信息:

  • ttf(total term frequency) :Term的总词频,即在所有文档中Term出现的总次数。可以看到twitter的ttf是2,test的ttf是4;
  • doc_freq(document frequency) :当前字段包含当前分词的文档的数量,可以看到两个document的text字段都包含test及twitter,所以两者的doc_freq为2;

默认情况下,不会返回这些信息,因为Term统计信息可能会对性 能产生严重影响。

3.3、字段统计信息

字段统计信息默认是返回的,可以将field_statistics设为false来 禁止返回。字段统计信息包括如下三方面的内容:

  • doc_count :文档计数,即多少个文档存在这个字段值。这里两个文档都包含text字段,所以doc_count为2;

  • sum_doc_freq :文档频率总和,当前字段中所有分词对应的document frequency的加和。 这里以下计算可以得到sum_doc_freq为6;

    202403132037389402.png

  • sum_ttf :Term频率总和,当前字段中所有分词对应的total term frequency的加和,这里以下计算可以得到sum_ttf为8;

    202403132037393893.png

4、Term过滤

使用参数filter,还可以根据tf-idf分数过滤返回的Term。这有助 于找出文档的特征向量。此功能的工作方式更类似于此查询的第二阶 段。

在下面的示例中,从具有给定plot字段值的文档中获得三个用户 “最感兴趣”的关键字。请注意,关键字Tony或任何停止词都不是响 应的一部分,因为它们的tf-idf太低。

    GET /imdb/_termvectors
    {
        "doc": {
          "plot": "When wealthy industrialist Tony Stark is forced to build an armored suit after a life-threatening incident, he ultimately decides to use its technology to fight against evil."
        },
        "term_statistics" : true,
        "field_statistics" : true,
        "positions": false,
        "offsets": false,
        "filter" : {
          "max_num_terms" : 3,
          "min_term_freq" : 1,
          "min_doc_freq" : 1
        }
    }

返回:

    {
       "_index": "imdb",
       "_type": "_doc",
       "_version": 0,
       "found": true,
       "term_vectors": {
          "plot": {
             "field_statistics": {
                "sum_doc_freq": 3384269,
                "doc_count": 176214,
                "sum_ttf": 3753460
             },
             "terms": {
                "armored": {
                   "doc_freq": 27,
                   "ttf": 27,
                   "term_freq": 1,
                   "score": 9.74725
                },
                "industrialist": {
                   "doc_freq": 88,
                   "ttf": 88,
                   "term_freq": 1,
                   "score": 8.590818
                },
                "stark": {
                   "doc_freq": 44,
                   "ttf": 47,
                   "term_freq": 1,
                   "score": 9.272792
                }
             }
          }
       }
    }

可以在请求中传递以下子参数:

  • max_num_terms:每个字段返回的最大Term数。默认值 为25。也就是只有一个字段最多25个Term。
  • min_term_freq:忽略源文档中低于此频率的单词。默认值 为1。
  • max_term_freq:忽略源文档中超过此频率的单词。默认为 无限大。
  • min_doc_freq:忽略文档频率低于这个值的Term。默认值 为1。
  • max_doc_freq:忽略文档频率高于这个值的Term。默认值 为1。
  • min_word_length:忽略低于此值的Term。默认值为0。
  • max_word_length:忽略高于此值的Term。默认值为无穷 大。

5、行为分析

Term和Field统计信息是不准确的,仅检索请求文档所在的分片 的信息,而删除的文档不考虑在内。因此,Term和Field统计信息仅 用作相对测量,而绝对数值在此上下文中没有意义。默认情况下,当 请求人工文档的Term向量时,将随机选择一个分片来获取统计信息。 使用routing只命中特定的分片。

5.1、返回存储Term向量

以下请求返回ID为1的文档(john doe)中字段text的所有信息 和统计信息:

    GET /twitter/_termvectors/1
    {
      "fields" : ["text"],
      "offsets" : true,
      "payloads" : true,
      "positions" : true,
      "term_statistics" : true,
      "field_statistics" : true
    }
    {
      "_index" : "twitter",
      "_type" : "_doc",
      "_id" : "1",
      "_version" : 1,
      "found" : true,
      "took" : 0,
      "term_vectors" : {
        "text" : {
          "field_statistics" : {
            "sum_doc_freq" : 6,
            "doc_count" : 2,
            "sum_ttf" : 8
          },
          "terms" : {
            "test" : {
              "doc_freq" : 2,
              "ttf" : 4,
              "term_freq" : 3,
              "tokens" : [
                {
                  "position" : 1,
                  "start_offset" : 8,
                  "end_offset" : 12,
                  "payload" : "d29yZA=="
                },
                {
                  "position" : 2,
                  "start_offset" : 13,
                  "end_offset" : 17,
                  "payload" : "d29yZA=="
                },
                {
                  "position" : 3,
                  "start_offset" : 18,
                  "end_offset" : 22,
                  "payload" : "d29yZA=="
                }
              ]
            },
            "twitter" : {
              "doc_freq" : 2,
              "ttf" : 2,
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 0,
                  "start_offset" : 0,
                  "end_offset" : 7,
                  "payload" : "d29yZA=="
                }
              ]
            }
          }
        }
      }
    }

5.2、动态生成Term向量

未存储在索引中的字段的Term向量将自动动态计算。以下请求返 回ID为1的文档中字段的所有信息和统计信息,即使这些Term尚未显式存储在索引中。请注意,对于字段text,不会重新生成Term向量。

    PUT /twitter/_doc/3
    {
      "fullname" : "Jane Doe",
      "text" : "Another twitter test ...",
      "filed_without_term_vector": "hello world"
    }
    
    GET /twitter/_termvectors/3
    {
      "fields" : ["text", "filed_without_term_vector"],
      "offsets" : true,
      "positions" : true,
      "term_statistics" : true,
      "field_statistics" : true
    }
    {
      "_index" : "twitter",
      "_type" : "_doc",
      "_id" : "3",
      "_version" : 1,
      "found" : true,
      "took" : 0,
      "term_vectors" : {
        "text" : {
          "field_statistics" : {
            "sum_doc_freq" : 10,
            "doc_count" : 3,
            "sum_ttf" : 12
          },
          "terms" : {
            "..." : {
              "doc_freq" : 2,
              "ttf" : 2,
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 3,
                  "start_offset" : 21,
                  "end_offset" : 24,
                  "payload" : "d29yZA=="
                }
              ]
            },
            "another" : {
              "doc_freq" : 2,
              "ttf" : 2,
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 0,
                  "start_offset" : 0,
                  "end_offset" : 7,
                  "payload" : "d29yZA=="
                }
              ]
            },
            "test" : {
              "doc_freq" : 3,
              "ttf" : 5,
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 2,
                  "start_offset" : 16,
                  "end_offset" : 20,
                  "payload" : "d29yZA=="
                }
              ]
            },
            "twitter" : {
              "doc_freq" : 3,
              "ttf" : 3,
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 1,
                  "start_offset" : 8,
                  "end_offset" : 15,
                  "payload" : "d29yZA=="
                }
              ]
            }
          }
        },
        "filed_without_term_vector" : {
          "field_statistics" : {
            "sum_doc_freq" : 2,
            "doc_count" : 1,
            "sum_ttf" : 2
          },
          "terms" : {
            "hello" : {
              "doc_freq" : 1,
              "ttf" : 1,
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 0,
                  "start_offset" : 0,
                  "end_offset" : 5
                }
              ]
            },
            "world" : {
              "doc_freq" : 1,
              "ttf" : 1,
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 1,
                  "start_offset" : 6,
                  "end_offset" : 11
                }
              ]
            }
          }
        }
      }
    }

5.3、人工文档

可以为人工文档生成Term向量,即索引中不存在的文档。示例如 下:

    GET /twitter/_termvectors
    {
      "doc" : {
        "fullname" : "John Doe",
        "text" : "twitter test test test"
      }
    }
    {
      "_index" : "twitter",
      "_type" : "_doc",
      "_version" : 0,
      "found" : true,
      "took" : 0,
      "term_vectors" : {
        "text" : {
          "field_statistics" : {
            "sum_doc_freq" : 10,
            "doc_count" : 3,
            "sum_ttf" : 12
          },
          "terms" : {
            "test" : {
              "term_freq" : 3,
              "tokens" : [
                {
                  "position" : 1,
                  "start_offset" : 8,
                  "end_offset" : 12
                },
                {
                  "position" : 2,
                  "start_offset" : 13,
                  "end_offset" : 17
                },
                {
                  "position" : 3,
                  "start_offset" : 18,
                  "end_offset" : 22
                }
              ]
            },
            "twitter" : {
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 0,
                  "start_offset" : 0,
                  "end_offset" : 7
                }
              ]
            }
          }
        },
        "fullname" : {
          "field_statistics" : {
            "sum_doc_freq" : 6,
            "doc_count" : 3,
            "sum_ttf" : 6
          },
          "terms" : {
            "doe" : {
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 1,
                  "start_offset" : 5,
                  "end_offset" : 8
                }
              ]
            },
            "john" : {
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 0,
                  "start_offset" : 0,
                  "end_offset" : 4
                }
              ]
            }
          }
        }
      }
    }

5.4、字段分析器

此外,可以使用per_field_analyzer参数为不同的字段提供不同 的分析器,这对于以任何方式生成Term向量都很有用,特别是在使用 人工文档时。当为已经存储Term向量的字段提供分析器时,将重新生 成Term向量。

    GET /twitter/_termvectors
    {
      "doc" : {
        "fullname" : "John Doe",
        "text" : "twitter test test test"
      },
      "fields": ["fullname"],
      "per_field_analyzer" : {
        "fullname": "keyword"
      }
    }
    {
      "_index" : "twitter",
      "_type" : "_doc",
      "_version" : 0,
      "found" : true,
      "took" : 0,
      "term_vectors" : {
        "fullname" : {
          "field_statistics" : {
            "sum_doc_freq" : 6,
            "doc_count" : 3,
            "sum_ttf" : 6
          },
          "terms" : {
            "John Doe" : {
              "term_freq" : 1,
              "tokens" : [
                {
                  "position" : 0,
                  "start_offset" : 0,
                  "end_offset" : 8
                }
              ]
            }
          }
        }
      }
    }

6、获取多个文档的Term向量

_mtermvectors API允许一次获取多个文档的Term向量。由索 引_index和_id参数指定多个文档,从指定的文档中检索出Term向 量。但是文档也可以在请求本身中人工提供。

    //语法
    POST /_mtermvectors
    POST /<index>/_mtermvectors
    POST /_mtermvectors
    {
       "docs": [
          {
            "_index":"twitter",
             "_id": "2",
             "fields": [
                "message"
             ],
             "term_statistics": true
          },
          {
            "_index":"twitter",
             "_id": "1"
          }
       ]
    }

响应包括一个docs数组,此数组包含所有获取的Term向量。

    {
      "docs" : [
        {
          "_index" : "twitter",
          "_type" : "_doc",
          "_id" : "2",
          "_version" : 1,
          "found" : true,
          "took" : 0,
          "term_vectors" : { }
        },
        {
          "_index" : "twitter",
          "_type" : "_doc",
          "_id" : "1",
          "_version" : 1,
          "found" : true,
          "took" : 0,
          "term_vectors" : {
            "fullname" : {
              "field_statistics" : {
                "sum_doc_freq" : 6,
                "doc_count" : 3,
                "sum_ttf" : 6
              },
              "terms" : {
                "doe" : {
                  "term_freq" : 1,
                  "tokens" : [
                    {
                      "position" : 1,
                      "start_offset" : 5,
                      "end_offset" : 8,
                      "payload" : "d29yZA=="
                    }
                  ]
                },
                "john" : {
                  "term_freq" : 1,
                  "tokens" : [
                    {
                      "position" : 0,
                      "start_offset" : 0,
                      "end_offset" : 4,
                      "payload" : "d29yZA=="
                    }
                  ]
                }
              }
            },
            "text" : {
              "field_statistics" : {
                "sum_doc_freq" : 10,
                "doc_count" : 3,
                "sum_ttf" : 12
              },
              "terms" : {
                "test" : {
                  "term_freq" : 3,
                  "tokens" : [
                    {
                      "position" : 1,
                      "start_offset" : 8,
                      "end_offset" : 12,
                      "payload" : "d29yZA=="
                    },
                    {
                      "position" : 2,
                      "start_offset" : 13,
                      "end_offset" : 17,
                      "payload" : "d29yZA=="
                    },
                    {
                      "position" : 3,
                      "start_offset" : 18,
                      "end_offset" : 22,
                      "payload" : "d29yZA=="
                    }
                  ]
                },
                "twitter" : {
                  "term_freq" : 1,
                  "tokens" : [
                    {
                      "position" : 0,
                      "start_offset" : 0,
                      "end_offset" : 7,
                      "payload" : "d29yZA=="
                    }
                  ]
                }
              }
            }
          }
        }
      ]
    }

可以指定索引:

    POST /twitter/_mtermvectors
    {
       "docs": [
          {
             "_id": "2",
             "fields": [
                "message"
             ],
             "term_statistics": true
          },
          {
             "_id": "1"
          }
       ]
    }

如果所有请求的文档都在同一索引上,并且参数相同,则可以简 化请求:

    POST /twitter/_mtermvectors
    {
        "ids" : ["1", "2"],
        "parameters": {
        	"fields": [
             	"message"
          	],
          	"term_statistics": true
        }
    }

此外,可以为用户提供的文档生成Term向量。使用的映射由索引 _index确定。下面是具体的实例:

    POST /_mtermvectors
    {
       "docs": [
          {
             "_index": "twitter",
             "doc" : {
                "user" : "John Doe",
                "message" : "twitter test test test"
             }
          },
          {
             "_index": "twitter",
             "doc" : {
               "user" : "Jane Doe",
               "message" : "Another twitter test ..."
             }
          }
       ]
    }
阅读全文