【问题标题】:Elasticsearch proper way to escape spaces, ? doesn't work in all scenariosElasticsearch 逃避空间的正确方法,?并非在所有情况下都有效
【发布时间】:2018-06-27 21:46:39
【问题描述】:

我正在尝试使用空格进行搜索以在 elasticsearch 中正常工作,但在使其行为方式与在其他字段上相同时遇到了很多麻烦。

我有两个字段,NameAddresses.First().Line1,我希望能够搜索并在搜索中保留空格。例如,搜索Bob Smi* 将返回Bob Smith,而不仅仅是Bob

这适用于我的名称字段,方法是使用? 替换空格进行查询字符串搜索。我也在做一个通配符,所以我的最终查询是*bob?smi*

但是,当我尝试按 line1 进行搜索时,我没有得到任何结果。例如。 *4800* 返回带有 line1 的记录,例如 4800 Street,但是当我使用 4800 street 进行相同的转换以得到 *4800?street* 时,我没有得到任何结果。

以下是我的查询

{
  "from": 0,
  "size": 50,
  "query": {
    "bool": {
      "must": [
        {
          "query_string": {
            "query": "*4800?Street*",
            "fields": [
              "name",
              "addresses.line1"
            ]
          }
        }
      ]
    }
  }
}

不返回任何结果。

为什么*bob?smi* 会返回名称为Bob Smith 的结果,而*4800?street* 不会返回带有订单项4800 street 的结果?

以下是索引中两个字段的设置方式:

.Text(smd => smd.Name(c => c.Name).Analyzer(ElasticIndexCreator.SortAnalyzer).Fielddata())

.Nested<Address>(nomd => nomd.Name(p => p.PrimaryAddress).Properties(MapAddressProperties))

//from MapAddressProperties()

.Text(smd2 => smd2.Name(x => x.Line1).Analyzer(ElasticIndexCreator.SortAnalyzer).Fielddata())

弹性映射:

"name": {
    "type": "text",
        "fields": {
            "keyword": {
                "type": "keyword",
                "ignore_above": 256
            }
        }
    }
}
"addresses": {
    "line1": {
        "type": "text",
        "fields": {
            "keyword": {
                "type": "keyword",
                "ignore_above": 256
            }
        }
    },
 }

是否有其他更好的方法来转义 elasticsearch 查询字符串中的空格?我也试过 \\\\\\(在 C# 中计算为 \\)而不是 ? 无济于事。

【问题讨论】:

  • 您是否考虑过使用匹配词组或匹配词组前缀查询?考虑到您迄今为止提出的用例,这似乎更符合您的要求:elastic.co/guide/en/elasticsearch/reference/current/…
  • 这似乎只适用于一个领域。我有很多要搜索的字段,这只是其中 2 个的示例。
  • 我已经阅读了你的帖子好几次,但我不确定我是否理解这里的要求。搜索其中的空格,但同时尝试使用??供您参考,要完全按照您看到的方式搜索4800 street,您需要使用"query": "\"4800 street\""。将文本用双引号括起来,以便完全按照这种方式进行搜索。
  • 关于*bob?smi*,匹配的确切查询和文档是什么?因为您提供的示例 - Bob Smithname 和对 *bob?smi* 的搜索不会返回匹配项。
  • 如果您在name.keyword 中搜索"query": "*Bob?Smi*",您的文档和query_string 将返回一些内容。

标签: c# elasticsearch elasticsearch-5


【解决方案1】:

经过大量时间的实验,终于找到了正确的设置。对我有用的配置如下:

  1. 在列中使用带有字段数据的文本
  2. 使用带有通配符占位符的 QueryString 进行搜索,将空格替换为 ?,例如输入bob smith,使用*bob?smith*查询弹性
  3. 对子对象使用嵌套查询。奇怪的是,addresses.line1 会在搜索 4800 时返回数据,但在尝试搜索 *4800?street* 时不会返回数据。使用嵌套查询可以使其正常运行。

据我所知,必须使用字段数据非常占用内存,而必须使用通配符非常耗时,因此这可能不是最佳解决方案,但它是我发现的唯一解决方案。如果有其他更好的方法可以做到这一点,请赐教。

使用 Nest 的 C# 查询示例:

var query = Query<Student>.QueryString(qs => qs
                .Fields(f => f
                .Field(c => c.Name)
                //.Field(c => c.PrimaryAddress.Line1) //this doesn't work
                )
                .Query(testCase.Term)
            );

query |= Query<Student>.Nested(n => n
        .Path(p => p.Addresses)
            .Query(q => q
                .QueryString(qs => qs
                        .Fields(f => f.Field(c => c.Addresses.First().Line1))
                        .Query(testCase.Term)
                    )
            )
        );

示例映射:

.Map<Student>(s => s.Properties(p => p
    .Text(t => t.Name(z => z.Name).Fielddata())
    .Nested<StudentAddress>(n => n
        .Name(ap => ap.Addresses)
        .Properties(ap => ap.Text(t => t.Name(z => z.Line1).Fielddata())
    )
))

【讨论】:

    【解决方案2】:

    尝试在fields参数term-level wildcard query中使用addresses.line1.keyword(即尝试您为addresses.line1定义的keyword多字段):

    {
        "query": {
            "wildcard": {
                "addresses.line1.keyword": {
                    "wildcard": "*4800 street*"
                }
            }
        }
    }
    

    根据Elasticsearch documentation on full-text wildcard searches,如果您搜索addresses.line1(其类型为text,因此适用全文搜索规则),将针对字段外分析的每个术语执行搜索,即一次针对4800street,没有一个匹配你的*4800?street* 通配符。 addresses.line1.keyword 多字段包含原始 4800 street 值,并且应该使用术语级通配符查询匹配您的查询模式。


    顺便说一句,一个小问题:addresses 字段的映射类型定义本身似乎不完整。你说的是:

    "addresses": {
        "line1": {
            "type": "text",
            "fields": {
                "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                }
            }
        },
    }
    

    但恕我直言,它应该是:

    "addresses": {
        "properties": {
            "line1": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                }
            },
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-05
      • 2017-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-13
      • 1970-01-01
      相关资源
      最近更新 更多