Document APIs之Term Vectors等

词条向量Term Vectors

返回特定文档字段中词条的信息和统计信息。文档可以存储在索引中,也可以由用户人工提供。默认情况下,词条向量是实时的,而不是接近实时的。这可以通过将realtime参数设置为false来更改。

GET /twitter/_termvectors/1

通过一个参数指定field来选择信息的返回这是可选的:

GET /twitter/_termvectors/1?fields=message

或通过在请求主体中添加请求的字段(参见下面的示例)。也可以使用通配符指定字段,类似于multi match查询

返回值

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

词条信息

  • 在字段中的词频(总是返回)
  • 词条位置(positions: true)
  • 开始与结束的偏移量(offsets: true)
  • 词条有效载荷(payloads: true),base64编码的字节

如果请求的信息没有存储在索引中,那么它将在可能的情况下动态计算。此外,甚至可以由用户提供,为索引中不存在的文档计算术语向量。

警告

开始和结束偏移量假设使用的是UTF-16编码。如果您想使用这些偏移量来获得生成此令牌的原始文本,则应该确保您正在获取的子字符串也使用UTF-16编码

词条统计

设置term_statistics为true(默认为false)将返回:

  • 总词频(所有文件中的词条频率)
  • 文档频率(包含词条的文档数)

默认情况下这些值不返回,因为词条统计数据会严重影响性能。

字段统计

将field_statistics设置为false(默认值为true)将省略:

  • 文档数(包含此字段的文档数)
  • 文档频率的总和(本字段中所有词条的文档频率的总和)
  • 词频的总和(该字段中每个词条的词频的总和)

词条过滤

使用参数筛选器,还可以根据tf-idf分数对返回的项进行筛选。这对于找出一个好的文档特征向量是很有用的。该特性的工作方式类似于第二个阶段的查询。有关用法,请参见示例5。

支持以下子参数:

参数名

描述

max_num_terms

每个字段必须返回的最大词条数。默认为25。

min_term_freq

在源文档中忽略少于此频率的单词。默认为1。

max_term_freq

在源文档中忽略超过此频率的单词。默认为无界。

min_doc_freq

忽略文档频率少于此参数的词条。默认为1。

max_doc_freq

忽略文档频率大于此参数的词条。默认为无界。

min_word_length

字词长度低于此参数的将被忽略。默认为0。

max_word_length

字词长度大于此参数的将被忽略。默认为无界(0)。

行为

词条和现场统计不准确。删除的文档将不被考虑。仅为所请求的文档所在的分片检索信息。因此,术语和字段统计仅作为相对的度量有用,而绝对值在这方面没有意义。默认情况下,在请求人工文档的词条向量时,随机选择一个碎片来获取统计信息。使用路由命中特定的分片。

示例:返回存储词条向量

首先,我们创建一个存储词条向量、有效载荷等的索引:

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"
          ]
        }
      }
    }
  }
}

然后,我们添加一些文档:

PUT /twitter/_doc/1
{
  "fullname" : "John Doe",
  "text" : "twitter test test test "
}

PUT /twitter/_doc/2
{
  "fullname" : "Jane Doe",
  "text" : "Another twitter test ..."
}

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

GET /twitter/_termvectors/1
{
  "fields" : ["text"],
  "offsets" : true,
  "payloads" : true,
  "positions" : true,
  "term_statistics" : true,
  "field_statistics" : true
}

响应:

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

示例:自动生成词条向量

没有显式存储在索引中的项向量将自动动态计算。下面的请求返回文档1中字段的所有信息和统计信息,即使这些术语没有显式地存储在索引中。注意,对于字段文本,不重新生成词条。

GET /twitter/_termvectors/1
{
  "fields" : ["text", "some_field_without_term_vectors"],
  "offsets" : true,
  "positions" : true,
  "term_statistics" : true,
  "field_statistics" : true
}

示例:人工文档

还可以为人工文档生成词条向量,即索引中不存在的文档。例如,下面的请求将返回与示例1相同的结果。使用的映射由索引决定。

如果打开动态映射(默认),将动态创建原始映射中没有的文档字段。

GET /twitter/_termvectors
{
  "doc" : {
    "fullname" : "John Doe",
    "text" : "twitter test test test"
  }
}

Per-field 分析器

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

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": 6,
  "term_vectors": {
    "fullname": {
       "field_statistics": {
          "sum_doc_freq": 2,
          "doc_count": 4,
          "sum_ttf": 4
       },
       "terms": {
          "John Doe": {
             "term_freq": 1,
             "tokens": [
                {
                   "position": 0,
                   "start_offset": 0,
                   "end_offset": 8
                }
             ]
          }
       }
    }
  }
}

示例:词条过滤

最后,返回的项可以根据tf-idf分数进行筛选。在下面的示例中,我们从具有给定“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
            }
         }
      }
   }
}

Multi termvectors API

Multi termvector API允许同时获得多个词条向量。检索词条向量的文档由索引和id指定。但是也可以在请求本身中人为地提供这些文档。

响应包括一个文档数组,其中包含所有获取的词条向量,每个元素都具有termvectors API提供的结构。举个例子:

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

有关可能的参数的描述,请参阅 termvectors API。

_mtermvector端点也可以用于索引(在这种情况下,在body中不需要它):

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
    }
}

此外,就像termvectors API一样,可以为用户提供的文档生成termvectors。使用的映射由_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 ..."
         }
      }
   ]
}

?refresh

Empty string or true

Index、Update、Delete和BulkAPI支持设置,以便在此请求所做的更改对搜索可见时进行控制。这些是允许的值:

Empty string or true

在操作发生后立即刷新相关的主分片和副本分片(而不是整个索引),以便更新后的文档立即出现在搜索结果中。只有在仔细考虑并验证它不会导致性能低下(无论是从索引还是搜索的角度)之后,才应该这样做。

wait_for

等待请求所做的更改在返回之前,被刷新为可见。这不会强制立即刷新,而是等待刷新发生。Elasticsearch自动刷新已更改每个索引的分片。refresh_interval,默认值为1秒。该设置是动态的。在任何支持刷新的API上调用Refresh API或将Refresh设置为true也会导致刷新,从而导致已运行中带有Refresh =wait_for的请求返回。

false (the default)

不采取刷新相关操作。此请求所做的更改将在请求返回后的某个时刻变得可见。

Choosing which setting to use

除非您有充分的理由等待更改变为可见,否则始终使用refresh=false,或者,因为这是缺省值,所以将refresh参数在URL上去除。这是最简单和最快的选择。

如果你一定要让所做的修改请求同步可见,那么必须在更多的负载于elasticsearch上(true)或更长的等待响应(wait_for)之间进行选择. 以下几点应有助于作出这一决定:

  • 与设置为true相比,wait_for能让索引做更多的变更工作,在这种情况下,每隔index.refresh_interval索引的修改只才会保存。
  • true将构造较小的有效的索引(微小段),以后必须将其合并到更有效的索引构造(较大的段)中。这意味着设置为true时,索引将花费时间在创建微小段上面,在搜索时从微小段进行搜索,并在合并时来制作较大段。
  • 不要在一行中启动多个refresh=wait_for请求。而是通过一个Bulk请求来使用refresh=wait_for,Elasticsearch将并行执行它们,并且只有当它们全部完成时才返回。
  • 如果刷新间隔设置为-1,禁用自动刷新,那么refresh=wait_for的请求将无限期等待,直到某个操作导致刷新。相反,设置index.refresh_interval小于默认值(如200ms)将使refresh=wait_for更快地返回,但它仍然会生成效率低下的段。
  • refresh=wait_for只影响正在运行的请求,但是,通过强制立即刷新refresh=true将影响其他正在进行的请求。通常,如果您有一个正在运行的系统,您不希望打扰它,那么refresh=wait_for是一个较小的修改。

refresh=wait_for Can Force a Refresh

如果一个refresh=wait_for请求进来,当已经有index.max_refresh_listeners(默认为1000)请求在等待该分片上的刷新时,那么该请求的行为就好像refresh设置为true:它将强制刷新。这保证了当refresh=wait_for请求返回,其更改对于搜索是可见的,同时防止对阻塞请求使用未检查的资源。如果一个请求因为耗尽了侦听器插槽而强制刷新,那么它的响应将包含“forced_refresh”:true。

Bulk请求只占用接触的每个分片上的一个slot,无论他们修改分片多少次

Examples

这些将创建一个文档,并立即刷新索引,使其可见:

PUT /test/_doc/1?refresh
{"test": "test"}
PUT /test/_doc/2?refresh=true
{"test": "test"}

这将创建一个文件,而不做任何事情,使其搜索可见:

PUT /test/_doc/3
{"test": "test"}
PUT /test/_doc/4?refresh=false
{"test": "test"}

这将创建一个文档并等待它成为搜索可见:

PUT /test/_doc/4?refresh=wait_for
{"test": "test"}

乐观并发控制

Elasticsearch是分布式的。当创建、更新或删除文档时,必须将文档的新版本复制到集群中的其他节点。Elasticsearch也是异步和并发的,这意味着这些复制请求是并行发送的,并且到达目的地的顺序可能不一致。Elasticsearch需要确保文档的旧版本不会覆盖新版本。

为了确保文档的旧版本不会覆盖新版本,对文档执行的每个操作都由协调该更改的主分片分配一个序列号。序列号随着每个操作的增加而增加,因此新操作的序列号一定比旧操作的序列号高。然后,Elasticsearch可以使用操作的序列号来确保新文档版本不会被分配了较小序列号的更改覆盖。

例如,下面的索引命令将创建一个文档,并为其分配一个初始序列号和primary term:

PUT products/_doc/1567
{
    "product" : "r2d2",
    "details" : "A resourceful astromech droid"
}

可以在响应的_seq_no和_primary_term字段中看到分配的序列号和primary term:

{
    "_shards" : {
        "total" : 2,
        "failed" : 0,
        "successful" : 1
    },
    "_index" : "products",
    "_type" : "_doc",
    "_id" : "1567",
    "_version" : 1,
    "_seq_no" : 362,
    "_primary_term" : 2,
    "result" : "created"
}

Elasticsearch跟踪要更改其存储的每个文档的最后一个操作的序号和主项。在GET API的响应中,在_seq_no和_primary_term字段中返回序列号和primary term:

GET products/_doc/1567

Response:

{
    "_index" : "products",
    "_type" : "_doc",
    "_id" : "1567",
    "_version" : 1,
    "_seq_no" : 362,
    "_primary_term" : 2,
    "found": true,
    "_source" : {
        "product" : "r2d2",
        "details" : "A resourceful astromech droid"
    }
}

注意:通过设置seq_no_primary_term参数,搜索API可以为每次搜索命中返回_seq_no和_primary_term。

序列号和primary term惟一地标识更改。通过记录返回的序列号和主项,您可以确保只在检索后没有对文档进行其他更改的情况下更改文档。这是通过设置index API或delete API的if_seq_no和if_primary_term参数来实现的。

例如,下面的索引调用将确保向文档添加一个标签,而不会丢失对描述的任何潜在更改,或由另一个API添加另一个标签:

PUT products/_doc/1567?if_seq_no=362&if_primary_term=2
{
    "product" : "r2d2",
    "details" : "A resourceful astromech droid",
    "tags": ["droid"]
}

 

你可能感兴趣的:(elasticsearch)