我有一个项目,它基于Symfony2,允许用户创建一些规则,用于将项目分配到不同的类别。它是一个后端项目,因此只有少数用户可以访问它。
规则基于短语,项目是文本对象。我试图找出一种最好的方法来尽可能快速,平稳地搜索和应用规则到那些文本对象。
例如,如果用户创建了5条规则(短语:basketball
,football
,baseball
,swimming
,running
)以及所有文字对象匹配任何这些短语都应该分配到SPORTS类别,我想我可以使用ElasticSearch快速返回这些对象的ID,然后使用简单的INSERT或UPDATE mysql查询保存赋值。
我担心性能,如果在索引中有例如1百万个文本对象,并且说有50k个对象匹配这些规则,在部分中运行搜索查询,例如将范围限制为50k ElasticSearch查询(迭代整个索引),然后更新/插入数据到MySQL是一种可接受的方法吗?
所以,运行查询(伪):
$ids = elasticSearch->setPhrases('basketball OR baseball OR football')->find()->limit(1, 50000);
$ids = elasticSearch->setPhrases('basketball OR baseball OR football')->find()->limit(50000, 100000);
等
ElasticSearch是否适合进行此类处理?或者我应该坚持MySQL并使用regexp运行查询(例如当然是块)?
也许我可以检查现有的解决方案?不幸的是,我只限于PHP和Symfony2,但如果有更好的解决方案值得检查,我可能会建议客户端。
希望有人能帮助我,欢迎任何帮助。
答案 0 :(得分:1)
假设您使用的是text
字段,则可以在桌面上创建FULLTEXT
索引:
CREATE TABLE texts(
id int not null auto_increment primary key,
text_field1 text,
text_field2 text,
text_field3 text
)Engine = MyISAM; -- InnoDB supports fulltext indexes since v5.6
CREATE FULLTEXT INDEX itexts on texts(text_field1,text_field2,text_field3);
然后你可以使用全文表达式搜索(找到至少一个术语):
SELECT * FROM texts
WHERE MATCH (text_field1,text_field2,text_field3)
AGAINST ('basketball baseball football');
或找到所有条款
SELECT * FROM texts
WHERE MATCH (text_field1,text_field2,text_field3)
AGAINST ('+basketball +baseball +football');
现在,在您的项目中,您可以将规则转换为全文搜索表达式,并使用常规的symfony查询执行它。
有关FULLTEXT搜索的更多信息: http://dev.mysql.com/doc/refman/5.0/en/fulltext-boolean.html
答案 1 :(得分:0)
这绝对是Elasticsearch所擅长的。例如,我的笔记本电脑上有一个索引(Macbook Air,所以没什么好吃的),它有4,095,005个代表不同名字的文件。
您请求的用例基本上只是完全匹配过滤。为此,我们可以使用非常快的Elasticsearch 过滤器。以下是一个查找五个不同名称的示例过滤器:
curl -XGET "http://localhost:9200/test_names/_search" -d'
{
"query": {
"filtered": {
"filter": {
"bool": {
"should": [
{
"term": {
"first_name": "miguel"
}
},
{
"term": {
"first_name": "ella"
}
},
{
"term": {
"first_name": "almeta"
}
},
{
"term": {
"first_name": "garret"
}
},
{
"term": {
"first_name": "simon"
}
}
]
}
}
}
}
}'
响应的顶部:
{
"took": 85,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3755,
"max_score": 1,
....
took: 85
意味着需要85毫秒来过滤400万个文档并找到匹配的3755.如果我再次运行相同的过滤器,我会得到:
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3755,
"max_score": 1,
....
现在执行时间只有4毫秒。这是因为Elasticsearch缓存了过滤器位集,因此后续搜索" miguel"," ella"," almeta"," garret"或者"西蒙"将以极快的速度执行(直到这些值从缓存中逐出)
查询提供更强大的全文搜索功能,并根据文档的匹配程度对文档进行排名。所以你可以这样做:
curl -XGET "http://localhost:9200/test_names/_search" -d'
{
"query" : {
"match": {
"first_name": "miguel ella almeta garret simon"
}
}
}'
这基本上相当于" miguel OR ella OR almeta或garret或simon",但加权使得匹配更多术语的文档得分更高。它在54ms内执行(再次在我的笔记本电脑上搜索4m文件):
{
"took": 54,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3755,
"max_score": 0.8923058,
...
这只是触及Elasticsearch可以做的事情的表面。但我肯定会说它可以提供你所描述的功能,而且非常非常快。