在Elasticsearch中搜索句点和连字符分隔的字段

时间:2018-11-20 03:24:58

标签: python elasticsearch search

我正在尝试找到一种使用Elasticsearch查询以句点和连字符分隔的字段的方法。

我有一个这样的(MySQL)数据集(使用SQLAlchemy访问它):

id    text        tag
====================================
1     some-text   A.B.c3
2     more. text  A.B-C.c4
3     even more.  B.A-32.D-24.f9


首先使用ES进行搜索的主要原因是我想针对text字段进行查询。那部分很棒!


但是,(我认为)我希望tag像这样在倒排索引中显示(我可能不会考虑大小写,仅出于说明目的而包括在内):

A.B.c3            1
A.B-C.c4          2
B.A-C2.D-24.f9    3

然后,我要像这样搜索tag字段:

{ "query": {
      "prefix" : { "tag" : "A.B" }
    }
}

并使查询返回id /行/文档1和2。

基本上,我希望查询匹配此真值表中的索引:

"A." = 1, 2
"A-" = 3

如何在开始时同时完成“ A.”匹配,区分句号和连字符(可能要加倍),并根据相同的分隔符匹配中间短语?

如果可能的话,如果这些匹配出现在tag字段的开头,我也希望对其进行加权。

我该怎么做,还是Elasticsearch不是适合该工作的工具?看来Elasticsearch对于我在通常分隔的英文文本上进行文本字段比较非常有效,但是基于标签的搜索似乎要困难得多。

更新:看来,当我仅对搜索返回的结果的一部分数据进行索引时,但对整个数据集进行查询时,我得到的点击率就会降低。

2 个答案:

答案 0 :(得分:1)

这可以通过N-Gram标记程序来完成。

根据您所提供的内容,我创建了其对应的映射,文档和示例查询,以为您提供所需的内容。

映射

PUT idtesttag
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "ngram",
          "min_gram": 2,
          "max_gram": 5
        }
      }
    }
  },
  "mappings": {
    "mydocs": {
      "properties": {
        "id": {
          "type": "long"
        },
        "text": {
          "type": "text",
          "analyzer": "my_analyzer"
        },
        "tag": {
          "type": "text",
          "analyzer": "my_analyzer"
        }
      }
    }
  }
}

这将是什么,如果您有一个带有id = 1的文档且带有标签A.B,它将在其反向索引中存储以下字符组。

 A. -> 1
 .B -> 1
A.B -> 1

因此,如果您的查询包含这三个词中的任何一个,则将返回带有id=1的文档。

样本文件

POST idtesttag/mydocs/1
{
  "id": 1,
  "text": "some-text",
  "tag": "A.B.c3"
}

POST idtesttag/mydocs/2
{
  "id": 2,
  "text": "more. text",
  "tag": "A.B-C.c4"
}

POST idtesttag/mydocs/3
{
  "id": 3,
  "text": "even more.",
  "tag": "B.A-32.D-24.f9"
}

POST idtesttag/mydocs/4
{
  "id": 3,
  "text": "even more.",
  "tag": "B.A.B-32.D-24.f9"
}

样本查询

POST idtesttag/_search
{
  "query": {
    "match": {
      "tag": "A.B"
    }
  }
}

查询响应

{
  "took": 139,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 3,
    "max_score": 0.8630463,
    "hits": [
      {
        "_index": "idtesttag",
        "_type": "mydocs",
        "_id": "1",
        "_score": 0.8630463,
        "_source": {
          "id": 1,
          "text": "some-text",
          "tag": "A.B.c3"
        }
      },
      {
        "_index": "idtesttag",
        "_type": "mydocs",
        "_id": "2",
        "_score": 0.66078395,
        "_source": {
          "id": 2,
          "text": "more. text",
          "tag": "A.B-C.c4"
        }
      },
      {
        "_index": "idtesttag",
        "_type": "mydocs",
        "_id": "4",
        "_score": 0.46659434,
        "_source": {
          "id": 3,
          "text": "even more.",
          "tag": "B.A.B-32.D-24.f9"
        }
      }
    ]
  }
}

请注意,文档1、2和4在响应中返回。 document 4句子中的匹配,而文档1 & 2则位于开头。

还要注意分数值的显示方式。

基于hypen的提升

现在关于基于hypen字符的增强,我建议您与Bool一起进行Regex Query with Boosting查询。以下是我想出的示例查询。

请注意,为简单起见,我添加了正则表达式,仅当hypen位于A.B旁边时,它才会增强。

POST idtesttag/_search
{
  "query": {
    "bool": {
      "must" : {
        "match" : { "tag" : "A.B" }
      },
      "should": [
        {
          "regexp": {
            "tag": {
              "value": "A.B-.*",
              "boost": 3
            }
          }
        }
      ]
    }
  }
}

提升查询响应

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 3,
    "max_score": 3.660784,
    "hits": [
      {
        "_index": "idtesttag",
        "_type": "mydocs",
        "_id": "2",
        "_score": 3.660784,
        "_source": {
          "id": 2,
          "text": "more. text",
          "tag": "A.B-C.c4"
        }
      },
      {
        "_index": "idtesttag",
        "_type": "mydocs",
        "_id": "4",
        "_score": 3.4665942,
        "_source": {
          "id": 3,
          "text": "even more.",
          "tag": "B.A.B-32.D-24.f9"
        }
      },
      {
        "_index": "idtesttag",
        "_type": "mydocs",
        "_id": "1",
        "_score": 0.8630463,
        "_source": {
          "id": 1,
          "text": "some-text",
          "tag": "A.B.c3"
        }
      }
    ]
  }
}

仅需确保在进行增强测试时就能够进行彻底的测试,因为这完全会影响得分,并确保您使用DEV / TEST Elastic index中引入的产品数据来进行测试。

这样一来,如果您转向PROD Elastic,则在看到完全不同的结果时不会被惊吓。

很抱歉,我的回答很长,但是希望对您有所帮助!

答案 1 :(得分:0)

  

但是,(我认为)我希望标签以这种方式出现在倒排索引中(我可能不会考虑大小写,只是为了说明而将其包括在内):

     

然后,我要像这样搜索标签字段:

根据您在帖子中的描述。 “标签”字段,这是我的2美分。

您的Mysql数据应为1种类型(在6.5中,默认为'doc')。不过,您确实需要明确定义索引映射-尤其是在“标签”字段上,因为您似乎有搜索要求。

我将您的“标签”字段定义为以下内容的多字段:

  • 键入“关键字”进行汇总
  • 使用自定义分析器(可能使用“空白”令牌生成器和“边缘ngram”令牌过滤器)键入“文本”进行搜索

(如果您不需要聚合,则只需使用自定义分析器定义一个“文本”类型字段)

仅供参考,Analyze API将向您展示ES在处理您的“标签”数据,并帮助您定义符合要求的映射。