我们有一个与OData兼容的API,它将某些全文搜索需求委托给Elasticsearch集群。由于OData表达式可能变得非常复杂,因此我们决定将它们简单地转换为等效的Lucene查询语法,并将其输入query_string
查询中。
我们确实支持一些与文本相关的OData过滤器表达式,例如:
startswith(field,'bla')
endswith(field,'bla')
substringof('bla',field)
name eq 'bla'
我们要匹配的字段可以是analyzed
,也可以是not_analyzed
两者(即通过多字段)。所搜索的文本可以是一个单一的令牌(例如table
),仅其一部分(例如tab
),或数个标记(例如table 1.
,table 10
等)。搜索必须不区分大小写。
以下是我们需要支持的行为的一些示例:
startswith(name,'table 1')
必须匹配“ 表1 ”,“ 表1 00”,“ 表1 .5”,“ 表1 12上层”endswith(name,'table 1')
必须与“ Room 1, Table 1 ”,“ Sub table 1 ”,“ table 1 ”,“ Jeff table 1 ” 匹配substringof('table 1',name)
必须匹配“大 表1 返回”,“ 表1 ”,“ 表1 ”,“小 表 1 2”name eq 'table 1'
必须匹配“ 表1 ”,“ 表1 ”,“ 表1 ”因此,基本上,我们接受用户输入(即,传递给startswith
/
的第二个参数endswith
,分别代表的1st参数和substringof
,代表右侧值eq
),并尝试完全匹配它们,即令牌是否完全匹配或仅部分。
目前,我们正在使用下面突出显示的笨拙解决方案,该解决方案效果很好,但远非理想。
在我们中query_string
,我们not_analyzed
使用正则表达式语法匹配字段。由于该字段为not_analyzed
,并且搜索必须不区分大小写,因此我们在准备将正则表达式馈入查询时进行了自己的标记化处理,以得出类似这样的信息,即,这等效于OData过滤器endswith(name,'table8')
(=> match name
以“表8”结尾的所有文档)
"query": {
"query_string": {
"query": "name.raw:/.*(T|t)(A|a)(B|b)(L|l)(E|e) 8/",
"lowercase_expanded_terms": false,
"analyze_wildcard": true
}
}
因此,尽管此解决方案效果很好,并且性能还不错(这出乎意料),但我们还是想做不同的事情,并利用分析仪的全部功能来转移索引时的所有负担。时间而不是搜索时间。但是,由于重新索引所有数据将需要数周的时间,因此我们想首先调查一下是否有令牌过滤器和分析器的良好组合,可以帮助我们达到上述相同的搜索要求。
我的想法是,理想的解决方案应包含带状疱疹(即多个令牌在一起)和edge-nGram(即在令牌的开头或结尾进行匹配)的某种明智的混合。不过,我不确定的是是否有可能使它们协同工作以匹配多个令牌,而其中一个令牌可能无法由用户完全输入)。例如,如果索引名称字段是“BigTable123”,则需要对其substringof('table 1',name)
进行匹配,因此“ table”是完全匹配的标记,而“
1”只是下一个标记的前缀。
在此先感谢您分享您的脑细胞。
更新1:测试安德烈的解决方案后
=>完全匹配(eq
),效果startswith
完美。
小endswith
故障
搜索substringof('table 112', name)
产生107文档。搜索更具体的情况(例如endswith(name, 'table 112')
产生1525个文档),而它会产生较少的文档(后缀匹配应该是子字符串匹配的子集)。更深入地检查,我发现了一些不匹配的地方,例如“ SocialClub,Table 12”(不包含“ 112”)或“ Order 312”(既不包含“ table”也不包含“ 112”)。我猜是因为它们以“12”结尾,并且这是令牌“ 112”的有效语法,因此是匹配项。
小substringof
故障
正在搜索substringof('table',name)
匹配项“ Party table”,“ Alex on big table”,但不匹配“
Table 1”,“ table 112”等。搜索substringof('tabl',name)
不匹配任何内容
更新2
这有点隐含,但我忘了明确提及该解决方案必须与query_string
查询一起使用,主要是因为OData表达式(无论它们可能是多么复杂)将一直转换为它们的Lucene等效项。我知道我们正在使用Lucene的查询语法来权衡ElasticsearchQuery DSL的功能,后者的功能和表现力都稍差一些,但这是我们无法真正改变的。不过,我们已经很接近了!
更新3(2019年6月25日):
ES7.2引入了一种称为的新数据类型search_as_you_type
,该数据类型本身就允许这种行为。有关更多信息,请访问:https ://www.elastic.co/guide/en/elasticsearch/reference/7.2/search-as-you-
type.html
这是一个有趣的用例。这是我的看法:
{
"settings": {
"analysis": {
"analyzer": {
"my_ngram_analyzer": {
"tokenizer": "my_ngram_tokenizer",
"filter": ["lowercase"]
},
"my_edge_ngram_analyzer": {
"tokenizer": "my_edge_ngram_tokenizer",
"filter": ["lowercase"]
},
"my_reverse_edge_ngram_analyzer": {
"tokenizer": "keyword",
"filter" : ["lowercase","reverse","substring","reverse"]
},
"lowercase_keyword": {
"type": "custom",
"filter": ["lowercase"],
"tokenizer": "keyword"
}
},
"tokenizer": {
"my_ngram_tokenizer": {
"type": "nGram",
"min_gram": "2",
"max_gram": "25"
},
"my_edge_ngram_tokenizer": {
"type": "edgeNGram",
"min_gram": "2",
"max_gram": "25"
}
},
"filter": {
"substring": {
"type": "edgeNGram",
"min_gram": 2,
"max_gram": 25
}
}
}
},
"mappings": {
"test_type": {
"properties": {
"text": {
"type": "string",
"analyzer": "my_ngram_analyzer",
"fields": {
"starts_with": {
"type": "string",
"analyzer": "my_edge_ngram_analyzer"
},
"ends_with": {
"type": "string",
"analyzer": "my_reverse_edge_ngram_analyzer"
},
"exact_case_insensitive_match": {
"type": "string",
"analyzer": "lowercase_keyword"
}
}
}
}
}
}
}
my_ngram_analyzer
用于将每个文本分成小块,块的大小取决于您的用例。我出于测试目的选择了25个字符。lowercase
因为您说不区分大小写,所以使用了。基本上,这是用于的标记器substringof('table 1',name)
。查询很简单: {
"query": {
"term": {
"text": {
"value": "table 1"
}
}
}
}
my_edge_ngram_analyzer
用于从头开始拆分文本,这专门用于startswith(name,'table 1')
用例。同样,查询很简单: {
"query": {
"term": {
"text.starts_with": {
"value": "table 1"
}
}
}
}
endswith(name,'table1')
。为此,我定义my_reverse_edge_ngram_analyzer
了将分keyword
词器与lowercase
,edgeNGram
过滤器一起使用的过滤reverse
器。该标记器的基本作用是将文本拆分为edgeNGrams,但edge是文本的结尾,而不是开始(就像常规一样edgeNGram
)。查询: {
"query": {
"term": {
"text.ends_with": {
"value": "table 1"
}
}
}
}
name eq 'table1'
情况,应使用简单的keyword
标记lowercase
器和过滤器来执行查询: {
"query": {
"term": {
"text.exact_case_insensitive_match": {
"value": "table 1"
}
}
}
}
关于 query_string
,这稍微改变了解决方案,因为我指望term
不分析输入文本,并使其与索引中的术语之一完全匹配。
但是,query_string
如果analyzer
为其指定了适当的位置,则可以“模拟” 。
解决方案将是一组类似以下的查询(始终使用该分析器,仅更改字段名称):
{
"query": {
"query_string": {
"query": "text.starts_with:(\"table 1\")",
"analyzer": "lowercase_keyword"
}
}
}
我们有一个OData兼容的API,它将一些全文搜索需求委托给一个Elasticsearch集群。由于OData表达式可能会变得相当复杂,我们决定简单地将它们转换为等效的Lucene查询语法,并将其提供给查询。 我们确实支持一些文本相关的OData过滤器表达式,比如: 我们匹配的字段可以是、或两者(即通过多字段)。所搜索的文本可以是单个令牌(例如)、仅是其一部分(例如)、或多个令牌(例如、等)。搜索
我想使用Impex从表中删除一些项目。下面的示例不会抛出错误,但不会删除任何内容。 查询产生预期的结果。是REMOVE与灵活的搜索不兼容,还是我遗漏了什么? 问题是,我正在hotfolder上运行导入,我想事先删除所有现有项目。我们欢迎其他解决方案。
我目前正在使用Spring security建立一个反向代理安全域,其想法是默认情况下要求所有请求上都有承载令牌,除了一些例外情况,如注册等。当前我的配置功能如下所示: Ant Matcher非常有用,但您必须单独传递所有URL。有没有办法让我传入一个字符串数组,这样我就可以将配置分开?
问题内容: 仅使用CSS,是否可以使元素的元素半透明,但元素的内容(文本和图像)不透明? 我想在没有文本和背景作为两个独立元素的情况下完成此操作。 尝试时: 子元素似乎受到其父对象的不透明性的影响,因此相对于父元素的父对象而言。 问题答案: 使用半透明的PNG图片或使用CSS 3:
我询问两件事。首先,我有一个ttf文件,它位于我的macair驱动器中。我不想将该文件添加到我的项目结构中。如何从中导入True_type字体。我尝试了各种方法将其导入我的Java程序。例如,公共类TextFixer{ 私有静态字符串[]名称 = { " iksswgrg.ttf " }; //这存在于我的macair驱动器上,我想从它创建字体。 第二部分是我想使用图形创建一个字符串。首先,我需要
我对灵活的查询有问题。这是我的疑问: 这是我执行时的错误: 有人能帮我吗?谢谢。