全文搜索

我们已经介绍了搜索结构化数据的简单应用示例,现在来探寻 全文搜索(full-text search) :怎样在全文字段中搜索到最相关的文档。

全文搜索两个最重要的方面是:

相关性(Relevance)

它是评价查询与其结果间的相关程度,并根据这种相关程度对结果排名的一种能力,这种计算方式可以是 TF/IDF 方法(参见 相关性的介绍)、地理位置邻近、模糊相似,或其他的某些算法。

分析(Analysis)

它是将文本块转换为有区别的、规范化的 token 的一个过程,(参见 分析的介绍) 目的是为了(a)创建倒排索引以及(b)查询倒排索引。

一旦谈论相关性或分析这两个方面的问题时,我们所处的语境是关于查询的而不是过滤。

基于词项与基于全文

所有查询会或多或少的执行相关度计算,但不是所有查询都有分析阶段。 和一些特殊的完全不会对文本进行操作的查询(如 bool 或 function_score )不同,文本查询可以划分成两大家族:

基于词项的查询

如 term 或 fuzzy 这样的底层查询不需要分析阶段,它们对单个词项进行操作。用 term 查询词项 Foo 只要在倒排索引中查找 准确词项 ,并且用 TF/IDF 算法为每个包含该词项的文档计算相关度评分 _score 。

记住 term 查询只对倒排索引的词项精确匹配,这点很重要,它不会对词的多样性进行处理(如, foo或 FOO )。这里,无须考虑词项是如何存入索引的。如果是将 ["Foo","Bar"] 索引存入一个不分析的( not_analyzed )包含精确值的字段,或者将 Foo Bar 索引到一个带有 whitespace 空格分析器的字段,两者的结果都会是在倒排索引中有 Foo 和 Bar 这两个词。

基于全文的查询

像 match 或 query_string 这样的查询是高层查询,它们了解字段映射的信息:

  • 如果查询 日期(date) 或 整数(integer) 字段,它们会将查询字符串分别作为日期或整数对待。
  • 如果查询一个( not_analyzed )未分析的精确值字符串字段, 它们会将整个查询字符串作为单个词项对待。
  • 但如果要查询一个( analyzed )已分析的全文字段, 它们会先将查询字符串传递到一个合适的分析器,然后生成一个供查询的词项列表。

一旦组成了词项列表,这个查询会对每个词项逐一执行底层的查询,再将结果合并,然后为每个文档生成一个最终的相关度评分。

我们将会在随后章节中详细讨论这个过程。

我们很少直接使用基于词项的搜索,通常情况下都是对全文进行查询,而非单个词项,这只需要简单的执行一个高层全文查询(进而在高层查询内部会以基于词项的底层查询完成搜索)。

当我们想要查询一个具有精确值的 not_analyzed 未分析字段之前, 需要考虑,是否真的采用评分查询,或者非评分查询会更好。

单词项查询通常可以用是、非这种二元问题表示,所以更适合用过滤, 而且这样做可以有效利用缓存

GET /_search

    {

        "query": {

            "constant_score": {

                "filter": {

                    "term": { "gender": "female" }

                }

            }

        }

    }

匹配查询

匹配查询 match 是个 核心 查询。无论需要查询什么字段, match 查询都应该会是首选的查询方式。 它是一个高级 全文查询 ,这表示它既能处理全文字段,又能处理精确字段。

这就是说, match 查询主要的应用场景就是进行全文搜索,我们以下面一个简单例子来说明全文搜索是如何工作的:

索引一些数据

首先,我们使用 bulk API 创建一些新的文档和索引:

DELETE /my_index 

PUT /my_index

    { "settings": { "number_of_shards": 1 }} 

POST /my_index/my_type/_bulk

    { "index": { "_id": 1 }}

    { "title": "The quick brown fox" }

    { "index": { "_id": 2 }}

    { "title": "The quick brown fox jumps over the lazy dog" }

    { "index": { "_id": 3 }}

    { "title": "The quick brown fox jumps over the quick dog" }

    { "index": { "_id": 4 }}

    { "title": "Brown fox brown dog" }

  删除已有的索引。

  稍后,我们会在 被破坏的相关性! 中解释只为这个索引分配一个主分片的原因。

单个词查询

我们用第一个示例来解释使用 match 查询搜索全文字段中的单个词:

GET /my_index/my_type/_search
{
"query": {
"match": {
"title": "QUICK!"
}
}
}

Elasticsearch 执行上面这个 match 查询的步骤是:

  1. 检查字段类型 。

    标题 title 字段是一个 string 类型( analyzed )已分析的全文字段,这意味着查询字符串本身也应该被分析。

  2. 分析查询字符串 。

    将查询的字符串 QUICK! 传入标准分析器中,输出的结果是单个项 quick 。因为只有一个单词项,所以 match 查询执行的是单个底层 term 查询。

  3. 查找匹配文档 。

    用 term 查询在倒排索引中查找 quick 然后获取一组包含该项的文档,本例的结果是文档:1、2 和 3 。

  4. 为每个文档评分 。

    用 term 查询计算每个文档相关度评分 _score ,这是种将 词频(term frequency,即词 quick 在相关文档的 title 字段中出现的频率)和反向文档频率(inverse document frequency,即词 quick 在所有文档的 title 字段中出现的频率),以及字段的长度(即字段越短相关度越高)相结合的计算方式。参见 相关性的介绍 。

这个过程给我们以下(经缩减)结果:

"hits": [

     {

        "_id":      "1",

        "_score":   0.5,  

        "_source": {

           "title": "The quick brown fox"

        }

     },

     {

        "_id":      "3",

        "_score":   0.44194174,  

        "_source": {

           "title": "The quick brown fox jumps over the quick dog"

        }

     },

     {

        "_id":      "2",

        "_score":   0.3125,  

        "_source": {

           "title": "The quick brown fox jumps over the lazy dog"

        }

     }

    ]

  文档 1 最相关,因为它的 title 字段更短,即 quick 占据内容的一大部分。
  文档 3 比 文档 2 更具相关性,因为在文档 2 中 quick 出现了两次。

多词查询

如果我们一次只能搜索一个词,那么全文搜索就会不太灵活,幸运的是 match 查询让多词查询变得简单:

GET /my_index/my_type/_search
{
"query": {
"match": {
"title": "BROWN DOG!"
}
}
}

上面这个查询返回所有四个文档:

{

      "hits": [

         {

            "_id":      "4",

            "_score":   0.73185337, 

            "_source": {

               "title": "Brown fox brown dog"

            }

         },

         {

            "_id":      "2",

            "_score":   0.47486103, 

            "_source": {

               "title": "The quick brown fox jumps over the lazy dog"

            }

         },

         {

            "_id":      "3",

            "_score":   0.47486103,  

            "_source": {

               "title": "The quick brown fox jumps over the quick dog"

            }

         },

         {

            "_id":      "1",

            "_score":   0.11914785, 

            "_source": {

               "title": "The quick brown fox"

            }

         }

      ]

    }

  文档 4 最相关,因为它包含词 "brown" 两次以及 "dog" 一次。
   文档 2、3 同时包含 brown 和 dog 各一次,而且它们 title 字段的长度相同,所以具有相同的评分。
  文档 1 也能匹配,尽管它只有 brown 没有 dog 。

因为 match 查询必须查找两个词( ["brown","dog"] ),它在内部实际上先执行两次 term 查询,然后将两次查询的结果合并作为最终结果输出。为了做到这点,它将两个 term 查询包入一个 bool 查询中,详细信息见 布尔查询

以上示例告诉我们一个重要信息:即任何文档只要 title 字段里包含 指定词项中的至少一个词 就能匹配,被匹配的词项越多,文档就越相关。

提高精度

用 任意 查询词项匹配文档可能会导致结果中出现不相关的长尾。 这是种散弹式搜索。可能我们只想搜索包含 所有 词项的文档,也就是说,不去匹配 brown OR dog ,而通过匹配 brown AND dog 找到所有文档。

match 查询还可以接受 operator 操作符作为输入参数,默认情况下该操作符是 or 。我们可以将它修改成 and 让所有指定词项都必须匹配

GET /my_index/my_type/_search

    {

        "query": {

            "match": {

                "title": {      

                    "query":    "BROWN DOG!",

                    "operator": "and" 

                }

            }

        }

    }

 match 查询的结构需要做稍许调整才能使用 operator 操作符参数。

这个查询可以把文档 1 排除在外,因为它只包含两个词项中的一个。

控制精度

在 所有 与 任意 间二选一有点过于非黑即白。 如果用户给定 5 个查询词项,想查找只包含其中 4 个的文档,该如何处理?将 operator 操作符参数设置成 and 只会将此文档排除。

有时候这正是我们期望的,但在全文搜索的大多数应用场景下,我们既想包含那些可能相关的文档,同时又排除那些不太相关的。换句话说,我们想要处于中间某种结果。

match 查询支持 minimum_should_match 最小匹配参数, 这让我们可以指定必须匹配的词项数用来表示一个文档是否相关。我们可以将其设置为某个具体数字,更常用的做法是将其设置为一个百分数,因为我们无法控制用户搜索时输入的单词数量:

GET /my_index/my_type/_search
{
"query": {
"match": {
"title": {
"query": "quick brown dog",
"minimum_should_match": "75%"
}
}
}
}

当给定百分比的时候, minimum_should_match 会做合适的事情:在之前三词项的示例中, 75% 会自动被截断成 66.6% ,即三个里面两个词。无论这个值设置成什么,至少包含一个词项的文档才会被认为是匹配的。

参数 minimum_should_match 的设置非常灵活,可以根据用户输入词项的数目应用不同的规则。完整的信息参考文档https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-minimum-should-match.html#query-dsl-minimum-should-match

为了完全理解 match 是如何处理多词查询的,我们就需要查看如何使用 bool 查询将多个查询条件组合在一起。

组合查询

在 组合过滤器 中,我们讨论过如何使用 bool 过滤器通过 and 、 or 和 not 逻辑组合将多个过滤器进行组合。在查询中, bool 查询有类似的功能,只有一个重要的区别。

过滤器做二元判断:文档是否应该出现在结果中?但查询更精妙,它除了决定一个文档是否应该被包括在结果中,还会计算文档的 相关程度 。

与过滤器一样, bool 查询也可以接受 must 、 must_not 和 should 参数下的多个查询语句。比如:

GET /my_index/my_type/_search
{
"query": {
"bool": {
"must": { "match": { "title": "quick" }},
"must_not": { "match": { "title": "lazy" }},
"should": [
{ "match": { "title": "brown" }},
{ "match": { "title": "dog" }}
]
}
}
}

以上的查询结果返回 title 字段包含词项 quick 但不包含 lazy 的任意文档。目前为止,这与 bool 过滤器的工作方式非常相似。

区别就在于两个 should 语句,也就是说:一个文档不必包含 brown 或 dog 这两个词项,但如果一旦包含,我们就认为它们 更相关 :

{

      "hits": [

         {

            "_id":      "3",

            "_score":   0.70134366, 

            "_source": {

               "title": "The quick brown fox jumps over the quick dog"

            }

         },

         {

            "_id":      "1",

            "_score":   0.3312608,

            "_source": {

               "title": "The quick brown fox"

            }

         }

      ]

    }

  文档 3 会比文档 1 有更高评分是因为它同时包含 brown 和 dog 。

评分计算

bool 查询会为每个文档计算相关度评分 _score , 再将所有匹配的 must 和 should 语句的分数 _score求和,最后除以 must 和 should 语句的总数。

must_not 语句不会影响评分; 它的作用只是将不相关的文档排除。

控制精度

所有 must 语句必须匹配,所有 must_not 语句都必须不匹配,但有多少 should 语句应该匹配呢? 默认情况下,没有 should 语句是必须匹配的,只有一个例外:那就是当没有 must 语句的时候,至少有一个 should 语句必须匹配。

就像我们能控制 match 查询的精度 一样,我们可以通过 minimum_should_match 参数控制需要匹配的 should 语句的数量, 它既可以是一个绝对的数字,又可以是个百分比:

GET /my_index/my_type/_search

    {

      "query": {

        "bool": {

          "should": [

            { "match": { "title": "brown" }},

            { "match": { "title": "fox"   }},

            { "match": { "title": "dog"   }}

          ],

          "minimum_should_match": 2 

        }

      }

    }

  这个查询结果会将所有满足以下条件的文档返回: title 字段包含 "brown" AND "fox" 、 "brown" AND "dog" 或 "fox" AND "dog" 。如果有文档包含所有三个条件,它会比只包含两个的文档更相关。

如何使用布尔匹配

目前为止,可能已经意识到多词 match 查询只是简单地将生成的 term 查询包裹 在一个 bool 查询中。如果使用默认的 or 操作符,每个 term 查询都被当作 should 语句,这样就要求必须至少匹配一条语句。以下两个查询是等价的:

{
"match": { "title": "brown fox"}
}
{
"bool": {
"should": [
{ "term": { "title": "brown" }},
{ "term": { "title": "fox" }}
]
}
}

如果使用 and 操作符,所有的 term 查询都被当作 must 语句,所以 所有(all) 语句都必须匹配。以下两个查询是等价的:

{
"match": {
"title": {
"query": "brown fox",
"operator": "and"
}
}
}
{
"bool": {
"must": [
{ "term": { "title": "brown" }},
{ "term": { "title": "fox" }}
]
}
}

如果指定参数 minimum_should_match ,它可以通过 bool 查询直接传递,使以下两个查询等价:

{
"match": {
"title": {
"query": "quick brown fox",
"minimum_should_match": "75%"
}
}
}

{

      "bool": {

        "should": [

          { "term": { "title": "brown" }},

          { "term": { "title": "fox"   }},

          { "term": { "title": "quick" }}

        ],

        "minimum_should_match": 2  

      }

    }

  因为只有三条语句,match 查询的参数 minimum_should_match 值 75% 会被截断成 2 。即三条 should 语句中至少有两条必须匹配。

当然,我们通常将这些查询用 match 查询来表示,但是如果了解 match 内部的工作原理,我们就能根据自己的需要来控制查询过程。有些时候单个 match 查询无法满足需求,比如为某些查询条件分配更高的权重。我们会在下一小节中看到这个例子。

ElasticSearch中query should与同于filter should

bool query should:一个文档不必包含 should 中的词项,但如果一旦包含,我们就认为它们 更相关 ;

bool filter should:返回的命中文档至少须匹配其中一个过滤器的条件。

bool  query should 中的 minimum_should_match:1 使用效果,相当于bool filter中should;且只能紧跟bool query中的should后面使用,其它位置会报异常。

查询语句提升权重

当然 bool 查询不仅限于组合简单的单个词 match 查询, 它可以组合任意其他的查询,以及其他 bool 查询。 普遍的用法是通过汇总多个独立查询的分数,从而达到为每个文档微调其相关度评分 _score 的目的。

假设想要查询关于 “full-text search(全文搜索)” 的文档, 但我们希望为提及 “Elasticsearch” 或 “Lucene” 的文档给予更高的 权重 ,这里 更高权重 是指如果文档中出现 “Elasticsearch” 或 “Lucene” ,它们会比没有的出现这些词的文档获得更高的相关度评分 _score ,也就是说,它们会出现在结果集的更上面。

一个简单的 bool 查询 允许我们写出如下这种非常复杂的逻辑:

GET /_search

    {

        "query": {

            "bool": {

                "must": {

                    "match": {

                        "content": { 

                            "query":    "full text search",

                            "operator": "and"

                        }

                    }

                },

                "should": [ 

                    { "match": { "content": "Elasticsearch" }},

                    { "match": { "content": "Lucene"        }}

                ]

            }

        }

    }

  content 字段必须包含 full 、 text 和 search 所有三个词。
  如果 content 字段也包含 Elasticsearch 或 Lucene ,文档会获得更高的评分 _score 。

should 语句匹配得越多表示文档的相关度越高。目前为止还挺好。

但是如果我们想让包含 Lucene 的有更高的权重,并且包含 Elasticsearch 的语句比 Lucene 的权重更高,该如何处理?

我们可以通过指定 boost 来控制任何查询语句的相对的权重, boost 的默认值为 1 ,大于 1 会提升一个语句的相对权重。所以下面重写之前的查询:

GET /_search

    {

        "query": {

            "bool": {

                "must": {

                    "match": {  

                        "content": {  

                            "query":    "full text search",

                            "operator": "and"

                        }

                    }

                },

                "should": [

                    { "match": {

                        "content": {

                            "query": "Elasticsearch",

                            "boost": 3  

                        }

                    }},

                    { "match": {

                        "content": {

                            "query": "Lucene",

                            "boost": 2  

                        }

                    }}

                ]

            }

        }

    }

  这些语句使用默认的 boost 值 1 。
  这条语句更为重要,因为它有最高的 boost 值。
  这条语句比使用默认值的更重要,但它的重要性不及 Elasticsearch 语句。

boost 参数被用来提升一个语句的相对权重( boost 值大于 1 )或降低相对权重( boost值处于 0 到 1 之间),但是这种提升或降低并不是线性的,换句话说,如果一个 boost 值为 2 ,并不能获得两倍的评分 _score 。

相反,新的评分 _score 会在应用权重提升之后被 归一化 ,每种类型的查询都有自己的归一算法,细节超出了本书的范围,所以不作介绍。简单的说,更高的 boost 值为我们带来更高的评分 _score 。

如果不基于 TF/IDF 要实现自己的评分模型,我们就需要对权重提升的过程能有更多控制,可以使用 function_score 查询操纵一个文档的权重提升方式而跳过归一化这一步骤。

更多的组合查询方式会在下章多字段搜索中介绍,但在此之前,让我们先看另外一个重要的查询特性:文本分析(text analysis)。

控制分析

查询只能查找倒排索引表中真实存在的项, 所以保证文档在索引时与查询字符串在搜索时应用相同的分析过程非常重要,这样查询的项才能够匹配倒排索引中的项。

尽管是在说 文档 ,不过分析器可以由每个字段决定。 每个字段都可以有不同的分析器,既可以通过配置为字段指定分析器,也可以使用更高层的类型(type)、索引(index)或节点(node)的默认配置。在索引时,一个字段值是根据配置或默认分析器分析的。

例如为 my_index 新增一个字段:

PUT /my_index/_mapping/my_type
{
"my_type": {
"properties": {
"english_title": {
"type": "text",
"analyzer": "english"
}
}
}
}

现在我们就可以通过使用 analyze API 来分析单词 Foxes ,进而比较 english_title 字段和 title 字段在索引时的分析结果:

GET/my_index/_analyze{

        "field": "my_type.title",

        "text": "Foxes",

        "analyzer": "standard " 

    }

GET/my_index/_analyze{

        "field": "my_type.english_title",

        "text": "Foxes",

        "analyzer": "english" 

    }

  字段 title ,使用默认的 standard 标准分析器,返回词项 foxes 
  字段 english_title ,使用 english 英语分析器,返回词项 fox

这意味着,如果使用底层 term 查询精确项 fox 时, english_title 字段会匹配但 title 字段不会。

如同 match 查询这样的高层查询知道字段映射的关系,能为每个被查询的字段应用正确的分析器。 可以使用 validate-query API 查看这个行为:

GET /my_index/my_type/_validate/query?explain
{
"query": {
"bool": {
"should": [
{ "match": { "title": "Foxes"}},
{ "match": { "english_title": "Foxes"}}
]
}
}
}

返回语句的 explanation 结果:

(title:foxes english_title:fox)

match 查询为每个字段使用合适的分析器,以保证它在寻找每个项时都为该字段使用正确的格式。

默认分析器

虽然我们可以在字段层级指定分析器, 但是如果该层级没有指定任何的分析器,那么我们如何能确定这个字段使用的是哪个分析器呢?

分析器可以从三个层面进行定义:按字段(per-field)、按索引(per-index)或全局缺省(global default)。Elasticsearch 会按照以下顺序依次处理,直到它找到能够使用的分析器。索引时的顺序如下:

  • 字段映射里定义的 analyzer ,否则
  • 索引设置中名为 default 的分析器,默认为
  • standard 标准分析器

在搜索时,顺序有些许不同:

  • 查询自己定义的 analyzer ,否则
  • 字段映射里定义的 analyzer ,否则
  • 索引设置中名为 default 的分析器,默认为
  • standard 标准分析器

有时,在索引时和搜索时使用不同的分析器是合理的。 我们可能要想为同义词建索引(例如,所有 quick出现的地方,同时也为 fast 、 rapid 和 speedy 创建索引)。但在搜索时,我们不需要搜索所有的同义词,取而代之的是寻找用户输入的单词是否是 quick 、 fast 、 rapid 或 speedy 。

为了区分,Elasticsearch 也支持一个可选的 search_analyzer 映射,它仅会应用于搜索时( analyzer 还用于索引时)。还有一个等价的 default_search 映射,用以指定索引层的默认配置。

如果考虑到这些额外参数,一个搜索时的 完整 顺序会是下面这样:

  • 查询自己定义的 analyzer ,否则
  • 字段映射里定义的 search_analyzer ,否则
  • 字段映射里定义的 analyzer ,否则
  • 索引设置中名为 default_search 的分析器,默认为
  • 索引设置中名为 default 的分析器,默认为
  • standard 标准分析器

分析器配置实践

就可以配置分析器地方的数量而言是十分惊人的, 但是实际非常简单。

保持简单

多数情况下,会提前知道文档会包括哪些字段。最简单的途径就是在创建索引或者增加类型映射时,为每个全文字段设置分析器。这种方式尽管有点麻烦,但是它让我们可以清楚的看到每个字段每个分析器是如何设置的。

通常,多数字符串字段都是 not_analyzed 精确值字段,比如标签(tag)或枚举(enum),而且更多的全文字段会使用默认的 standard 分析器或 english 或其他某种语言的分析器。这样只需要为少数一两个字段指定自定义分析:或许标题 title 字段需要以支持 输入即查找(find-as-you-type) 的方式进行索引。

可以在索引级别设置中,为绝大部分的字段设置你想指定的 default 默认分析器。然后在字段级别设置中,对某一两个字段配置需要指定的分析器。

对于和时间相关的日志数据,通常的做法是每天自行创建索引,由于这种方式不是从头创建的索引,仍然可以用 索引模板(Index Template) 为新建的索引指定配置和映射。

被破坏的相关度!

在讨论更复杂的 多字段搜索 之前,让我们先快速解释一下为什么只在主分片上 创建测试索引 。

用户会时不时的抱怨无法按相关度排序并提供简短的重现步骤: 用户索引了一些文档,运行一个简单的查询,然后发现明显低相关度的结果出现在高相关度结果之上。

为了理解为什么会这样,可以设想,我们在两个主分片上创建了索引和总共 10 个文档,其中 6 个文档有单词 foo 。可能是分片 1 有其中 3 个 foo 文档,而分片 2 有其中另外 3 个文档,换句话说,所有文档是均匀分布存储的。

在 什么是相关度?中,我们描述了 Elasticsearch 默认使用的相似度算法,这个算法叫做 词频/逆向文档频率 或 TF/IDF 。词频是计算某个词在当前被查询文档里某个字段中出现的频率,出现的频率越高,文档越相关。 逆向文档频率 将 某个词在索引内所有文档出现的百分数 考虑在内,出现的频率越高,它的权重就越低。

但是由于性能原因, Elasticsearch 不会计算索引内所有文档的 IDF 。 相反,每个分片会根据 该分片 内的所有文档计算一个本地 IDF 。

因为文档是均匀分布存储的,两个分片的 IDF 是相同的。相反,设想如果有 5 个 foo 文档存于分片 1 ,而第 6 个文档存于分片 2 ,在这种场景下, foo 在一个分片里非常普通(所以不那么重要),但是在另一个分片里非常出现很少(所以会显得更重要)。这些 IDF 之间的差异会导致不正确的结果。

在实际应用中,这并不是一个问题,本地和全局的 IDF 的差异会随着索引里文档数的增多渐渐消失,在真实世界的数据量下,局部的 IDF 会被迅速均化,所以上述问题并不是相关度被破坏所导致的,而是由于数据太少。

为了测试,我们可以通过两种方式解决这个问题。第一种是只在主分片上创建索引,正如 match 查询 里介绍的那样,如果只有一个分片,那么本地的 IDF 就是 全局的 IDF。

第二个方式就是在搜索请求后添加 ?search_type=dfs_query_then_fetch , dfs 是指 分布式频率搜索(Distributed Frequency Search) , 它告诉 Elasticsearch ,先分别获得每个分片本地的 IDF ,然后根据结果再计算整个索引的全局 IDF 。

不要在生产环境上使用 dfs_query_then_fetch 。完全没有必要。只要有足够的数据就能保证词频是均匀分布的。没有理由给每个查询额外加上 DFS 这步。

elasticsearch 深入 —— 全文检索的更多相关文章

  1. 《从Lucene到Elasticsearch:全文检索实战》学习笔记五

    今天我给大家讲讲tf-idf权重计算 tf-idf权重计算: tf-idf(中文词频-逆文档概率)是表示计算词项对于一个文档集或语料库中的一份文件的重要程度.词项的重要性随着它在文档中出现的次数成正比 ...

  2. 《从Lucene到Elasticsearch:全文检索实战》学习笔记四

    今天我给大家讲讲布尔检索模型基本概念 布尔检索模型: 检索模型是判断文档内容与用户相关性的核心技术,以大规模网页搜索为例,在海量网页中与用户查询关键词相关的网页可能会有成千上万个,甚至耕读哦.那么信息 ...

  3. 《从Lucene到Elasticsearch:全文检索实战》学习笔记三

    今天我给大家讲讲倒排索引. 索引是构成搜索引擎的核心技术之一,它在日常生活中是非常常见的,比如我看一本书的时候,我首先会看书的目录,通过目录可以快速定位到具体章节的页码,加快对内容的查询速度. 文档通 ...

  4. 《从Lucene到Elasticsearch:全文检索实战》学习笔记二

    今天我给大家讲讲分词算法 分词算法概述:词是语义的最小单位.分词对搜索引擎的作用很大,可以促进搜索引擎程序自动识别语句的含义,可以提高搜索结果的匹配度,分析的质量也将直接影响了搜索结果的精确度.分词存 ...

  5. 《从Lucene到Elasticsearch:全文检索实战》学习笔记一

    今天,我主要给大家讲一下信息检索概念. 信息检索: 互联网时代的飞速发展使人们进入了信息爆炸时代,据统计全球的互联网用户已达到30亿,在各个网站及移动app在每个分钟 产生的数据量是巨大的,从而导致数 ...

  6. Elasticsearch初步使用(安装、Head配置、分词器配置)

    目录 返回目录:http://www.cnblogs.com/hanyinglong/p/5464604.html 1.ElasticSearch简单说明 a.ElasticSearch是一个基于Lu ...

  7. elasticsearch 权威指南入门阅读笔记(一)

    相关文档 esapi:https://es.xiaoleilu.com/010_Intro/10_Installing_ES.html     https://esdoc.bbossgroups.co ...

  8. Elasticsearch(8) --- 聚合查询(Metric聚合)

    Elasticsearch(8) --- 聚合查询(Metric聚合) 在Mysql中,我们可以获取一组数据的 最大值(Max).最小值(Min).同样我们能够对这组数据进行 分组(Group).那么 ...

  9. Lucene的全文检索学习

    Lucene的官方网站(Apache的顶级项目):http://lucene.apache.org/ 1.什么是Lucene? Lucene 是 apache 软件基金会的一个子项目,由 Doug C ...

随机推荐

  1. 补比赛——牛客OI周赛9-普及组

    比赛地址 A 小Q想撸串 题目分析 普及T1水题惯例.字符串中找子串. Code #include<algorithm> #include<iostream> #include ...

  2. alert(1) to win 5

    function escape(s) { var text = s.replace(/</g, '<').replace(/"/g, '"'); // URLs tex ...

  3. AGC036C GP 2

    由于近期集训做的一直都是校内题 然后好久都怎么写题了( 发篇博客证明我还活着 (其实也没人关心 好像并不是很难的一道计数 就是脑子总是缺一块导致会做不出来( 首先我们可以分析性质 1.$\sum A_ ...

  4. flask之url_for函数

    一:url_for函数 干什么的?传入函数名,得到函数的路由地址(访问视图函数的地址) from flask import Flask from flask import url_for app = ...

  5. js undefined三目运算

    js ajax传值中 "id":$('#id').val(), 如果#id不存在,使用$('#id').val()||‘’,可避免向后台传入undefined

  6. 基于MaxCompute InformationSchema进行冷门表热门表访问分析

    一.需求场景分析 在实际的数据平台运营管理过程中,数据表的规模往往随着更多业务数据的接入以及数据应用的建设而逐渐增长到非常大的规模,数据管理人员往往希望能够利用元数据的分析来更好地掌握不同数据表的使用 ...

  7. 当 Messaging 遇上 Jepsen

    分布式系统面临的挑战 Is it better to be alive and wrong or right and dead? 随着计算机技术的发展,系统架构从集中式演进到分布式.分布式系统相对于单 ...

  8. JAVA WEB怎么实现大文件上传

    javaweb上传文件 上传文件的jsp中的部分 上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求 1.通过form表单向后端发送请求 改进后的代码不需要form标签,直 ...

  9. 学习日记3、投机取巧使两个表的数据同时在一个treeGrid中显示

    不多说了直接上代码, $('#List').treegrid({ url: '@Url.Action("GetList")', width: $(window).width() - ...

  10. XX-Net 使用教程(Across the Great Wall)

    注意: 由于封锁严重,软件自带IP已经被封杀殆尽.因此需要数分钟到数小时的初始化IP扫描,方能正常运行. 虽然系统内置了公共appid, 还是建议部署自己的appid,公共appid限制看视频.需要注 ...