假设我在SQL中有一个表,我将两个字段合并为一个
A | B
-----|-------- => select A+' '+ B as Name => BMW X-Series
BMW | 3-Series
BMW | X3
我将它转储到临时表中,然后在临时表上进行通配符搜索,返回带有计数的结果
select Name,count(Name) as frequency from Table where Name like '%3%' group by Name
Name Frequency
------------------
BMW 3-Series | 1
BMW X3 | 1
现在,如果A和B是单独的字段,我如何实现弹性搜索。
我试过了:
{ "query":{
"query_string":{
"fields":["A","B"],
"query":"3"
}
}, "aggs": {
"count": {
"terms": {
"field": "A"
},
"aggs": {
"count": {
"terms": {
"field": "B"
}
}
}
}
}
}
如何在查询
上添加正则表达式答案 0 :(得分:1)
SQL和Elasticsearch之间的主要区别在于,默认情况下,字符串字段在索引时分析,您可以使用Analyzers控制它们的分析方式。
默认分析器the Standard Analyzer将从输入生成标记并将它们存储在倒排索引中。您可以使用Analyze API:
查看为给定输入生成的令牌curl -XPOST "http://localhost:9200/_analyze?analyzer=standard" -d'
{
text : "3-Series"
}'
产生输出
{
"tokens": [
{
"token": "3",
"start_offset": 0,
"end_offset": 1,
"type": "<NUM>",
"position": 0
},
{
"token": "series",
"start_offset": 2,
"end_offset": 8,
"type": "<ALPHANUM>",
"position": 1
}
]
}
了解这一点,使用在搜索时进行分析的搜索查询,例如the Query String Query,无需regular expression queries或wildcard queries 如果您以支持用例的方式分析输入。
您可以决定在一个字段中对“宝马3系列”进行索引,并使用multi_fields以不同方式对其进行分析,或者将这些值保存在单独的字段中,然后搜索两者。
这是一个让你入门的例子。鉴于我们有以下POCO
public class Car
{
public string Make { get; set; }
public string Model { get; set; }
}
我们可以设置以下索引
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var carsIndex = "cars";
var connectionSettings = new ConnectionSettings(pool)
.DefaultIndex(carsIndex);
var client = new ElasticClient(connectionSettings);
client.CreateIndex(carsIndex, ci => ci
.Settings(s => s
.Analysis(analysis => analysis
.Tokenizers(tokenizers => tokenizers
.Pattern("model-tokenizer", p => p.Pattern(@"\W+"))
)
.TokenFilters(tokenfilters => tokenfilters
.WordDelimiter("model-words", wd => wd
.PreserveOriginal()
.SplitOnNumerics()
.GenerateNumberParts()
.GenerateWordParts()
)
)
.Analyzers(analyzers => analyzers
.Custom("model-analyzer", c => c
.Tokenizer("model-tokenizer")
.Filters("model-words", "lowercase")
)
)
)
)
.Mappings(m => m
.Map<Car>(mm => mm
.AutoMap()
.Properties(p => p
.String(s => s
.Name(n => n.Model)
.Analyzer("model-analyzer")
)
)
)
)
);
我们创建一个cars
索引,并创建一个用于Model
字段的自定义分析器。此自定义分析器将输入分为任何非单词字符上的标记,然后使用标记过滤器将每个标记拆分为数字字符以生成保留原始标记的标记,代表数字部分的标记和标记代表单词的部分。最后,所有代币都是小写的。
我们可以测试model-analyzer
对我们输入的作用,看看它是否适合我们的需求
curl -XPOST "http://localhost:9200/cars/_analyze?analyzer=model-analyzer" -d'
{
text : "X3"
}'
产生
{
"tokens": [
{
"token": "x3",
"start_offset": 0,
"end_offset": 2,
"type": "word",
"position": 0
},
{
"token": "x",
"start_offset": 0,
"end_offset": 1,
"type": "word",
"position": 0
},
{
"token": "3",
"start_offset": 1,
"end_offset": 2,
"type": "word",
"position": 1
}
]
}
和
curl -XPOST "http://localhost:9200/cars/_analyze?analyzer=model-analyzer" -d'
{
text : "3-Series"
}'
生成
{
"tokens": [
{
"token": "3",
"start_offset": 0,
"end_offset": 1,
"type": "word",
"position": 0
},
{
"token": "series",
"start_offset": 2,
"end_offset": 8,
"type": "word",
"position": 1
}
]
}
这看起来很适合手头的问题。现在,如果我们索引一些文档并执行搜索,我们应该得到我们正在寻找的结果
client.Index<Car>(new Car { Make = "BMW", Model = "3-Series" });
client.Index<Car>(new Car { Make = "BMW", Model = "X3" });
// refresh the index so that documents are available to search
client.Refresh(carsIndex);
client.Search<Car>(s => s
.Query(q => q
.QueryString(qs => qs
.Fields(f => f
.Field(c => c.Make)
.Field(c => c.Model)
)
.Query("3")
)
)
);
产生以下结果
{
"took" : 4,
"timed_out" : false,
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.058849156,
"hits" : [ {
"_index" : "cars",
"_type" : "car",
"_id" : "AVTbhENDDGlNKQ4qnluJ",
"_score" : 0.058849156,
"_source" : {
"make" : "BMW",
"model" : "3-Series"
}
}, {
"_index" : "cars",
"_type" : "car",
"_id" : "AVTbhEOXDGlNKQ4qnluK",
"_score" : 0.058849156,
"_source" : {
"make" : "BMW",
"model" : "X3"
}
} ]
}
}
希望这能给你一些想法。