从标题看,这几个都是重点知识,把这些都学会了,coreseek基本上使用无障碍了,所以很重要!!
1 、SPH_MATCH_ALL, 匹配所有查询词(默认模式);
2、SPH_MATCH_ANY,匹配查询词中的任意一个;
3、SPH_MATCH_PHRASE,将整个查询看作一个词组,要求按顺序完整匹配;
4、SPH_MATCH_BOOLEAN,将查询看作一个布尔表达式 (参见第 5.2节“布尔查询语法”);
5、SPH_MATCH_EXTENDED,将查询看作一个CoreSeek/Sphinx内部查询语言的表达式 (参见第 5.3 节“扩展查询语法”).从版本Coreseek 3/Sphinx 0.9.9开始,这个选项被选项SPH_MATCH_EXTENDED2代替,它提供了更多功能和更佳的性能。保留这个选项是为了与遗留的旧代码兼容——这样即使Sphinx及其组件包括API升级的时候,旧的应用程序代码还能够继续工作。
6、SPH_MATCH_EXTENDED2,使用第二版的“扩展匹配模式”对查询进行匹配.
7、SPH_MATCH_FULLSCAN,强制使用下文所述的“完整扫描”模式来对查询进行匹配。注意,在此模式下,所有的查询词都被忽略,尽管过滤器、过滤器范围以及分组仍然起作用,但任何文本匹配都不会发生。
Sphinx添加了相当多的匹配和rank模式,并且将添加更多。一些不同的问题经常被提出,从“我怎样让指定的文档排在第一位”到 “我怎么根据匹配度来评定星级”,实际处理要归结于内在的匹配和排序。
匹配方式有基础匹配模式和拓展的匹配模式。
Sphinx 1.10版本中使用的两个最重要的权重因子是:
1)经典统计学BM25因子,从80年代开始被大部分的搜索引擎使用,
2)Sphinx特有的短语相似因子。
根据Sphinx排序使用的准确算法,可以通过调整字段权重微调排序。
虽然排序因子可能是整型,布尔型,浮点数或者其他任何可能的值,但权重值一定是个单标量值。在Sphinx里,权重值是一个整数,浮点数权重值可以通过各种各样方法映射到一个整数值。
SphinxAPI 提供两个不同的方法,分别是 MatchMode 和RankingMode。
MatchMode 匹配模式都是为了遗留和兼容。而RankingMode模式是关于Sphinx计算相关度的。
在版本0.9.8之前,Sphinx只有匹配模式,并且每个匹配模式是用不同的代码路径实现。每个代码路径实现一组不同类型的匹配和排序。例如,SPH_MATCH_ALL要求所有的关键字都出现,并且只用phrase proximity计算文档的权重。SPH_MATCH_ANY要求任何关键字中的一个,并且用不同的方式计算文档权重等等。
在版本0.9.8中,开始启用一个全新的,统一的匹配引擎。为了避免在使用它工作时破坏兼容性,在版本0.9.8中,只提供一个独立的匹配模式,叫做SPH_MATCH_EXTENDED2。到版本0.9.9时,显然新的引擎已经变的稳定并且表现的足够好,因而我们赞成从新引擎中移除所有遗留的代码路径。因此从版本0.9.9开始,所有的查询都用统一的引擎处理,这跟之前的情况不同,而且维护困难(指之前维护困难)。因此实际上现在所有的匹配模式都只是历史遗留。
当然Sphinx仍然继续兼容那些遗留的模式,并且当你使用其中的一种时,它会自动转换成一个简单的查询短语代码(完全忽略查询语法)然后自动选择一种适当的排序模式。但其实本来就是这样。一切都是由统一的引擎处理,因此,文档权重(即@weight)只跟选择的rank模式有关。
例如,下面两个查询将得到完全一样的权重(同样一样的处理时间):
// 1st route
$cl->SetMatchMode ( SPH_MATCH_ALL );
$cl->Query ( "helloworld" );
// 2nd route
$cl->SetMatchMode ( SPH_MATCH_EXTENDED2 );
$cl->SetRankingMode ( SPH_RANK_PROXIMITY );
$cl->Query ("helloworld" );
注意第二种方法允许使用(@titlehello world)语法,因为这种匹配模式允许这样做。第一种是不允许的,因为在那种匹配模式中所有的特殊操作符会被忽略,@title会被当成一个关键字。
MatchMode 功能是过滤关键字和选择一个合适的排序。它相当于一个历史调用,因为将不会再有新的匹配模式。
RankingMode只是让你明确的指定一个排序方式。
rank模式介绍
rank模式,或者简称排序,可以正式的定义成函数:对一个给定的查询和文档参数计算相关值(权重)。
相关度基本上是主观的,因此没有一个适合所有的排序模式,将来也不会有。因此有多个不同的因子用于计算最终的权重,有无数的方法合并这些因子为一个权重,讨论这些是另外单独帖子的主题。
匹配模式
以官方C的API为例,sphinx自带的一些匹配模式如下:
匹配查询词中的任意一个。
通常想搜索到尽可能多的一句话中的内容,使用的是SPH_MATCH_ANY,但使用它之后,任何关键词中的字都可能做为一个单独的词进行搜索。这种匹配模式对词频也很有权重,这种搜索结果一般不是很准确
将整个查询参数看作一个词组,要求按顺序完整匹配才会搜索出结果,搜索时会过滤掉特殊符号,比较符合需要搜索出相关度最高的结果。
在创建连接对象时,设置:
sphinx_client *client;
client->mode=SPH_MATCH_PHRASE;
SPH_MATCH_ALL--匹配所有查询词
匹配所有查询词(默认模式)
在创建连接对象时,设置:
sphinx_client * client;
client->mode= SPH_MATCH_ALL;
将查询看作一个布尔表达式
将查询看作一个Sphinx内部查询语言的表达式
要搜索的关键词同时存在才会被搜索出来。因为SPHINX默认不是通过空格分词的。而是通过""来分。比如两个关键词:我们他是。
如果单这样写sphinx_query (client, “我们他是“, index, NULL );使用any模式会折成我 们 他 是 。似乎是一元分词法。而使用extended2则要搜索的字段同时存在这2个词才可以被搜索到。如果写成 sphinx_query ( client,("\"我们\"|\"他是\"",index);那么他就会分成我们和他是2个词。而且同时存在的权重会较高。
在创建连接对象时,设置:
sphinx_client *client;
client->mode=SPH_MATCH_EXTENDED2;
SPH_MATCH_FULLSCAN--完全扫描
使用完全扫描,忽略查询词汇
Rank模式
Rank模式为拓展的匹配模式。
以官方C的API为例,设置为拓展匹配模式SPH_MATCH_EXTENDED2后,请求的匹配方式将由其rank模式来决定。
可使用如下模式对匹配搜索结果:
禁用排序的模式,这是最快的模式。实际上这种模式与布尔搜索相同。所有的匹配项都被赋予权重1
排序模式只是简单的给每个文档赋权重为1.
weight = 1
为什么这样并且实际跳过所有的排序呢?答案就是性能。
如果你需要搜索结果按价格排序,那为什么要浪费CPU周期来处理耗时而你并不需要的排序呢。
排序模式计算所有的关键字出现的次数并乘以用户设置的字段权重。
weight = 0
foreach ( field inmatching_fields )
weight += num_keyword_occurrences ( field )
注意它计算所有关键字出现的次数,而不只是唯一的关键字。因此1个匹配的关键字出现3次和3个不同关键字出现1次是一样的。
SPH_RANK_FIELDMASK--匹配字段的位标识
排序模式返回一个匹配字段的位标识。
weight = 0
foreach ( field inmatching_fields )
set_bit ( weight, index_of ( field ) )
// or in otherwords, weight |= ( 1 << index_of ( field ) )
通过简单的短语相似算法得到一个权重值:
weight = doc_phrase_weight
由短语权重的定义可知,当文档匹配了查询但是没有保持匹配关键字的顺序,所有这样的文档的权重都为1.很显然,它跟建议使用的PROXIMITY_BM25排序模式得到的结果并没有区别。相关的搜索性能影响可以忽略不计。
短语相似,与上面BM25截然相反,根本不关心关键词出现的频率和查询关键词在文档中的位置。代替BM25使用的关键词频率,Sphinx分析关键词在每个字段的位置,并且用最长公共子串算法(LCS)计算关键词和文档的短语相似度。
基本上,每个字段的短语相似度就是一些关键词在文档中出现并且顺序和查询一致。这里是一些例子:
1) query = one twothree, field = one and two three
field_phrase_weight = 2 (because 2-keywordlong "two three" subphrase matched)
2) query = one twothree, field = one and two and three
field_phrase_weight = 1 (becausesingle keywords matched but no subphrase did)
3) query = one twothree, field = nothing matches at all
field_phrase_weight = 0
每个字段的短语权重将乘以每个字段的权重值,字段权重值通过调用SetFieldWeights() API或者在SphinxQL中的field_weights选项设置的,然后再全部相加起来生成每个文档的短语权重。
字段的默认权重值为1,不能设成小于1的值。整个短语相似算法的伪代码如下所示:
doc_phrase_weight = 0
foreach ( field inmatching_fields )
{
field_phrase_weight = max_common_subsequence_length ( query, field )
doc_phrase_weight += user_weight ( field ) * field_phrase_weight
}
Example:
doc_title = hello world
doc_body = the world is awonderful place
query = hello world
query_title_weight = 5
query_body_weight = 3
title_phrase_weight = 2
body_phrase_weight = 1
doc_phrase_weight = 2*5+3*1 = 13
正是由于短语相似因子保证了越相似的短语将排在前面,而精确匹配的短语将排在非常前面。可以使用字段权重值来调整排序,例如,上面例子中,匹配单个关键字的标题的权重值和匹配两个关键字短语的内容一样。
用来模拟匹配模式的MATCH_ANY模式,结合了短语相似算法和匹配关键字次数,因此每个字段默认权重,a)较长子短语匹配(即更大短语相似)在任何字段将获得更高的排序,b)与短语相似一致,文档匹配不同关键字越多则排名越高。换句话说,先看最大匹配子短语的长度,再看匹配不同关键字的数量。
伪代码如下:
k = 0
foreach ( field inall_fields )
k += user_weight ( field ) * num_keywords ( query )
weight = 0
foreach ( field inmatching_fields )
{
field_phrase_weight = max_common_subsequence_length ( query, field )
field_rank = ( field_phrase_weight * k + num_matching_keywords ( field ) )
weight += user_weight ( field ) * field_rank
}
它不使用BM25,因为遗留的模式没有使用,要保持兼容。
SPH_RANK_BM25--匹配关键字出现频率
排序模式计算匹配字段用户设置的权重和BM25的总和.
field_weights = 0
foreach ( field inmatching_fields )
field_weights += user_weight ( field )
weight = field_weights*1000 + integer(doc_bm25*999)
和PROXIMITY_BM25模式基本相似,除了用户权重没有乘以每个字段的短语相似值。不使用短语相似允许引擎只使用文档列表来评估搜索,跳过处理关键字出现。除非你的文档非常短(think tweets, titles, etc),关键字出现列表比文档列表大,并且需要更多的时间去处理。因此BM25比其他任何相似算法快。
同样,很多其他搜索系统默认使用BM25排序模式,或者有的只提供它做为唯一选择。因此当做性能测试展示的时候使用BM25排序可能有意义。
BM25是一个只依赖于匹配关键字出现频率的浮点数值。Frequencies in question are in-document and in-collectionfrequencies.基本上,关键字和/或在文档字段中出现多次,那个文档的权重越大,这是很罕见的。
统计相关度计算模式,仅使用 BM25 评分计算(与大多数全文检索引擎相同)。这个模式比较快,但是可能使包含多个词的查询的结果质量下降。
标准的BM25实现在Wikipedia article on BM25解释的非常明白,但是Sphinx使用的是稍微修改过的变体。首先,考虑到性能原因,我们计算所有的关键字在文档中出现的次数,而不只是计算匹配的关键字。例如(@title “hello world”)查询只在标题中匹配“hello world”的单一实例,它的BM25的计算结果和(hello world)查询一样,(hello world)查询文档中匹配所有同时出现关键字的实例。第二,我们不强制任何文档属性,因此不需要文档的长度,这样我们也忽略了文档长度(等于在原始的BM25中设置 b=0)。全部的变化都是内部的,在我们的测试中,使用原始BM25得到的计算结果不足够说明排序关联性能作用的改善。在Sphinx中使用的BM25计算算法的伪代码如下:
BM25 = 0
foreach ( keyword inmatching_keywords )
{
n = total_matching_documents ( keyword )
N = total_documents_in_collection
k1 = 1.2
TF = current_document_occurrence_count ( keyword )
IDF = log((N-n+1)/n) / log(1+N)
BM25 = BM25 + TF*IDF/(TF+k1)
}
// normalize to 0..1 range
BM25 = 0.5 + BM25 / ( 2*num_keywords ( query ) )
TF是指在一个文档中被排序的检索词频。它是基于在一个文档内关键字出现的次数,但是因为用对数函数平滑处理,因此出现1000次并不会得到1000倍的影响,而是1。
TF一般在0到1之间变化,但是在条件k=1.2的情况下,它实现的变化范围是0.4545…到1之间。
IDF是指在整个文档集中的反向文档频率。常见词(如“the” or “to”等)的IDF值小,罕见词的IDF值大,当一个关键词只在一个文档中出现时,达到峰值IDF=1,而当关键词在每个索引文档都出现时,IDF=-1。
因此,就像你上面看到的代码,BM25值当关键字出现频率小时会增大,相反在文档中频繁出现的话,BM25值会减小。要注意的是当关键词过度频繁匹配索引文档超过一半以上时会降低BM25的值!事实上,当一个关键词出现在90%的文档中而很少的文档没有包含关键词时,或许大概会更有趣,应该得到更大的权重。
怎样计算最大可能的权重
怎样计算最大可能的权重,然后根据返回的权重评定A-F等级,或者百分比,或者其他任何东西?
从前面的章节可以看到没有简单的办法可以实现。最大权重依靠于选择的排序模式和特定的查询。
例如,PROXIMITY_BM25模式权重的上界应该是
max_weight = num_keywords * sum ( user_field_weights ) * 1000 + 999
但这个上界可以达到吗?实际上几乎不可能,因为那需要a)精确短语匹配b)在所有的字段c)附加的BM25峰值达到999。
此外,如果查询使用字段权限符将会怎样?例如:@title hello world? 在那种情况我们的上界将永远不会被达到,因为我们除了标题字段外的其他字段都不会匹配。
强调需要字段
即可以使用一个适合你需求的排序模式,或者使用Sphinx运行时表达式来计算所需要的结果集并排序。
例子如下,把精确匹配排在前面可以用表达式模拟排序:
SELECT *, @weight+IF(fieldcrc==$querycrc,1000,0) AS myweight ...
ORDER BY myweight DESC
fieldcrc是CRC(field)属性在索引时计算并存在索引文件里,querycrc是在搜索时计算CRC(query)。
例子如下,代替严格检查CRC值匹配,你可以索引并保存字段长度,然后通过表达式把越短的字段排越前面
SELECT *, @weight+ln(len+1)*1000 AS myweight ...
例子,当搜索一个关键字时为了强制一个文档排的更靠前,你可以创建一个单独的字段,放超级重要的关键字,然后给这个字段赋一个很高的权重。(不要把权重设置超过1000000)
使用词组评分和 BM25 评分。
计算权重如下:
weight = doc_phrase_weight*1000 + integer(doc_bm25*999)
因此文档短语相似度是主要因子,BM25是辅助部分,当相同的短语相似时进行附加的文档排序。BM25在0到1之间,因此最终权重包含的最后3个数字是由BM25决定的,所有其他的数字用于短语权重。
如果需要要把结果精确匹配排在前面,更进一步改善PROXIMITY_BM25模式,版本1.10-beta中加入SPH04模式。
短语相似仍然是主导因素,但是当给定一个短语相似的时候,在字段最开始匹配将排序更高,如果是整个字段完全匹配的话将排到最高处。
例如,当查询“Market Street”,SPH04模式基本上将某个字段完全匹配“Market Street”的文档排序在最前面,接着排像“Market Street Grocery”这样在字段最开始匹配的文档,然后排像“WestMarket Street”这样在字段某处有与短语相匹配的文档,最后排那些有包含短语所有关键字但不是一个短语的文档(例如,“Flea Market on 26th Street”)。
伪代码如下,
field_weights = 0
foreach ( field inmatching_fields )
{
f = 4*max_common_subsequence_length ( query, field )
if ( exact_field_match ( query, field ) )
f += 3
else if ( first_keyword_matches ( query, field ) )
f += 2
field_weights += f * user_weight ( field )
}
weight = field_weights*1000 + integer(doc_bm25*999)
Rank因子分析
在1.10-beta版本,Sphinx有8种不同的排序模式,并且在将来还会添加更多的。每个排序模式计算得到不同的权重值,因此可能不会适合一个特殊的方案。
不同的rank模式使用一个或多个rank因子。
(1)短语相似度和BM25
短语相似度设计成比BM25需要更多的计算,因为它需要计算所有在文档中匹配的关键词,而不仅仅只计算文档本身。Sphinx默认使用短语相似算法,因为我们相信这个产生更好的搜索质量。当然你也可以选择使用一个更轻量级的排序器来省掉这些昂贵的相似计算。
短语相似和BM25是两个最重要的因子,最终的权重值是由排序模式决定的,一个或者多个因子经过特殊函数的处理得到一个值。
有两种遗留的排序模式(PROXIMITY,MATCHANY)是只依靠短语相似算法,并分别用于模拟MATCH_ALL 和MATCH_ANY两种遗留模式。
有三种排序模式(BM25,PROXIMITY_BM25, SPH04)是可以合并短语相似、BM25还有其他。SphinxQL现在默认是用PROXIMITY_BM25。BM25被推荐做为一个合适的快速排序模式,不亚于其他系统。SPH04是建立在PROXIMITY_BM25之上,但另外排序精确字段匹配,字段开头匹配比仅仅只是匹配等级高。
PROXIMITY_BM25 和 SPH04被期望产生最佳的质量,但是有可能需要特殊的结果。
(2)关键字次数
有三种简单的排序模式(NONE,WORDCOUNT, FIELDMASK)不做任何事,只统计关键字出现的次数,然后分别的返回匹配字段的位标识。它们在根本不需要排序或者由于应用端以某种方式计算时很有用。
(3)性能比较
选择的排序模式会严重影响搜索的性能。
NONE模式显明是最快的排序模式。
处理关键字位置(出现次数)是典型的最耗时的部分,因此不需要处理这部分的排序模式(FIELDMASK, BM25)总是比其他的快,也需要较少的磁盘IO(不需要读取位置)。
处理关键字位置的排序模式(WORDCOUNT,PROXIMITY, MATCHANY, PROXIMITY_BM25, SPH04)只在CPU影响上有所区别。
---------------------
作者:风云来
来源:CSDN
原文:https://blog.csdn.net/chenjiayi_yun/article/details/53619767
版权声明:本文为博主原创文章,转载请附上博文链接!
使用排序模式和文档属性对搜索结果排序。
已知的文档的内置属性:
@id (匹配文档的 ID)
@weight (匹配权值)
@rank (等同 weight)
@relevance (等同 weight)
@random (随机顺序返回结果)
其他的属性为用户设置属性。
以官方C的API为例,模式如下:
按相关度降序排列(最好的匹配排在最前面)
按属性降序排列 (属性值越大的越是排在前面)
按属性升序排列(属性值越小的越是排在前面)
先按时间段(最近一小时/天/周/月)降序,再按相关度降序
在SPH_SORT_TIME_SEGMENTS模式中,属性值被分割成“时间段”,然后先按时间段排序,再按相关度排序。
时间段是根据搜索发生时的当前时间戳计算的,因此结果随时间而变化。
时间段的分法固化在搜索程序中了,但如果需要,也可以比较容易地改变(需要修改源码)。
这种模式是为了方便对Blog日志和新闻提要等的搜索而增加的。使用这个模式时,处于更近时间段的记录会排在前面,但是在同一时间段中的记录又根据相关度排序-这不同于单纯按时间戳排序而不考虑相关度。
SPH_SORT_ATTR_ASC,SPH_SORT_ATTR_DESC以及SPH_SORT_TIME_SEGMENTS这三个模式仅要求一个属性名。
按一种类似SQL的方式将列组合起来,升序或降序排列。
在 SPH_SORT_EXTENDED 模式中,您可以指定一个类似SQL的排序表达式,但涉及的属性(包括内部属性)不能超过5个。
例如:
sphinx_set_sort_mode(client,SPH_SORT_EXTENDED,"@relevanceDESC, price ASC, @id DESC")
relevance和id是内部属性,而price是用户定义属性
只要做了相关设置,不管是内部属性(引擎动态计算出来的那些属性)还是用户定义的属性就都可以使用。内部属性的名字必须用特殊符号@开头,用户属性按原样使用就行了。
表达式排序模式使您可以对匹配项按任何算术表达式排序,表达式中的项可以是属性值,内部属性(id和weight),算术运算符和一些内建的函数。
例如:
sphinx_set_sort_mode(client,SPH_SORT_EXPR,"weight+ ( user_karma + ln(pageviews) )*0.1")
支持的运算符和函数为:运算符: +, -,*, /, <, >
算术表达式是模仿MySQL设计的。函数接受参数,参数的数目根据具体函数的不同而不同。
如果需要按照权重排序,可以使用以下方式:
按照字段命中计算权值
sphinx_set_match_mode( client,SPH_MATCH_EXTENDED2 );//设置匹配模式
sphinx_set_ranking_mode ( client, SPH_RANK_PROXIMITY);//设置评分模式
const char * field_names[3];
int field_weights[3];
field_names[0] = "industry";
field_weights[0] = 1;
field_names[1] = "area";
field_weights[1] = 2;
field_names[2] = "expr";
field_weights[2] = 2;
//设置字段的权重,如果area命中,那么权重算2
sphinx_set_field_weights ( client, 3, field_names, field_weights );
//按照权重排序
sphinx_set_sort_mode ( client, SPH_SORT_EXPR, "@weight");//内部属性的名字必须用特殊符号@开头
---------------------
作者:风云来
来源:CSDN
原文:https://blog.csdn.net/chenjiayi_yun/article/details/53619767
版权声明:本文为博主原创文章,转载请附上博文链接!
sphinx是一个非常强大的全文检索工具,
当然,它也支持php的API接口。
那么,
使用sphinx的php接口的时候,
如何指定字段进行搜索呢?
按如下两个步骤做就可以实现了:
1. 调用SetMatchMode()设置匹配模式mode为SPH_MATCH_EXTENDED;
2. 在调用Query()查询的时候,第一个参数在搜索关键词前加上指定字段的字符串@+字段名+空格,如:@title 手机;
// 建立连接
$sphinx = new SphinxClient ();
$sphinx->SetServer ( $server, $port );
$sphinx->SetSortMode(SPH_SORT_EXTENDED, "attr_total desc");
// 连接超时时间(非常必要,比如sphinx服务器挂了等异常情况) 单位为s,秒
$sphinx->SetConnectTimeout ( 3 );
// 最大查询时间 单位为ms,毫秒
$sphinx->SetMaxQueryTime ( 2000 );
// 按分页取结果
$sphinx->SetLimits ( ($page - 1) * $pageSize, $pageSize ); //第一个参数为offset,第二个参数为limit
// 模式
$sphinx->SetMatchMode(SPH_MATCH_EXTENDED);
//$sphinx->SetMatchMode(SPH_MATCH_EXTENDED2);//扩展匹配模式
//$sphinx->SetMatchMode(SPH_MATCH_FULLSCAN);//完整扫描
// 取到的原始数据
$orgDatas = $sphinx->Query ("@pcate ".$keyword, $indexName );
这里不能用@attr_pcate,切记
问题提出:
在购物或者是视频网站中,经常会看到聚类搜索,什么按照城市、类别、用途、爱好之类,这种可以是多选
问题解决:
1.mysql的where查询, 缺点:对于分裂的库表无能为力
2.sphinx
sphinx可以实现多字段查询,而且还可以通过属性进行排序、过滤等操作。(请注意,索引是不可以全文搜索的,因而要做全文搜索的字段一定不能作为索引)
具体可见sphinx文档:
************************************************************************************************************************************************************************
3.2. 属性
属性是附加在每个文档上的额外的信息(值),可以在搜索的时候用于过滤和排序。
搜索结果通常不仅仅是进行文档的匹配和相关度的排序,经常还需要根据其他与文档相关联的值,对结果进行额外的处理。例如,用户可能需要对新闻检索结果依次按日期和相关度排序,检索特定价格范围内的产品,检索某些特定用户的blog日志,或者将检索结果按月分组。为了高效地完成上述工作,Sphinx允许给文档附加一些额外的属性,并把这些值存储在全文索引中,以便在对全文匹配结果进行过滤、排序或分组时使用。
属性与字段不同,不会被全文索引。他们仅仅是被存储在索引中,属性进行全文检索式不可能的。如果要对属性进行全文检索,系统将会返回一个错误。
例如,如果column被设置为属性,就不能使用扩展表达式@column 1去匹配column为1的文档;如果数字字段按照普通的方式被索引,那么就可以这样来匹配。
属性可用于过滤,或者限制返回的数据,以及排序或者 结果分组; 也有可能是完全基于属性排序的结果, 而没有任何搜索相关功能的参与. 此外, 属性直接从搜索服务程序返回信息, 而被索引的文本内容则没有返回.
论坛帖子表是一个很好的例子。假设只有帖子的标题和内容这两个字段需要全文检索,但是有时检索结果需要被限制在某个特定的作者的帖子或者属于某个子论坛的帖子中(也就是说,只检索在SQL表的author_id和forum_id这两个列上有特定值的那些行),或者需要按post_date列对匹配的结果排序,或者根据post_date列对帖子按月份分组,并对每组中的帖子计数。
为实现这些功能,可以将上述各列(除了标题和内容列)作为属性做索引,之后即可使用API调用来设置过滤、排序和分组。以下是一个例子:
示例: sphinx.conf 片段:
sql_query = SELECT id, title, content, \
author_id, forum_id, post_date FROM my_forum_posts
sql_attr_uint = author_id
sql_attr_uint = forum_id
sql_attr_timestamp = post_date
示例: 应用程序代码 (PHP):
// only search posts by author whose ID is 123
$cl->SetFilter ( "author_id", array ( 123 ) );
// only search posts in sub-forums 1, 3 and 7
$cl->SetFilter ( "forum_id", array ( 1,3,7 ) );
// sort found posts by posting date in descending order
$cl->SetSortMode ( SPH_SORT_ATTR_DESC, "post_date" );
---------------------
作者:cleanfield
来源:CSDN
原文:https://blog.csdn.net/cleanfield/article/details/7029860
字段开始和字段结束修饰符 (在版本Coreseek 3.1/Sphinx 0.9.9-rc2中引入),其中“^”为开始符,“$”为结尾符,有点类似正则表达式。
在sql_query中,取出一字段以逗号隔开的整型串 cate_ids 如:
SELECT CONCAT(IF(dc.`cate_id` is NULL,0,dc.`cate_id`),',',IF(dc2.`cate_id` is NULL,0,dc2.`cate_id`),',',IF(dc3.`cate_id` is NULL,0,dc3.`cate_id`),',',IF(dc4.`cate_id` is NULL,0,dc4.`cate_id`)) AS cate_ids
FROM mytable mt
LEFT JOIN cate dc ON dc.cate_id = mt.cate_id
LEFT JOIN cate dc2 ON dc.parent_id = dc2.cate_id
LEFT JOIN cate dc3 ON dc2.parent_id = dc3.cate_id
LEFT JOIN cate dc4 ON dc3.parent_id = dc4.cate_id
再设置sql_attr_multi属性如下:
sql_attr_multi = uint ids from field cate_ids
或直接
sql_attr_multi = uint ids from query;\
SELECT docid, cate_id FROM cate WHERE 1 ORDER BY docid ASC; \
mysql中,每一个文档都有多个标签,查询时可以筛选一个标签也可以筛选同时拥有多个标签的文档。
数据示例
文档 标签
1 1,2,3,4,5
2 2,3,4,5,6
3 3,4,5,6,7
4 4,5,6,7,8
5 5,6,7,8,9
注意:
这里将文档id和标签tagid的对应关系存入了fy_content_tag表,一个id对应多条tagid记录
查询要求
1、查出拥有标签2的文档
2、查出同时拥有标签2,3,4的文档
使用sphinx解决需求
1、配置shpinx mva多值属性
编辑sphinx配置文件,给数据源增加一个多值属性
sql_attr_multi = uint tagid from query;\
SELECT id,tagid FROM fy_content_tag
2、执行查询
使用API中的setFilter即可。
1、查出拥有标签2的文档
$sphinx->setFilter('tagid', array(2));
2、查出同时拥有标签2,3,4的文档
$sphinx->setFilter('tagid', array(2));
$sphinx->setFilter('tagid', array(3));
$sphinx->setFilter('tagid', array(4));
这里解释一下:
$sphinx->setFilter(‘tagid’, array(2,3,4));
是表示含有标签值2,3,4中的任意一个即符合筛选,这里是or关系。
$sphinx->setFilter(‘tagid’, array(2));
$sphinx->setFilter(‘tagid’, array(3));
$sphinx->setFilter(‘tagid’, array(4));
设置三个filter是标示,要同时满足2,3,4三个属性值才符合,这里是and关系。
Sphinx sql_attr_multi配置参考
在Sphinx中,有一个MVA属性,声明格式如下(用反斜线只是为了清晰,您仍可以在一行之内完成声明):
sql_attr_multi = ATTR-TYPE ATTR-NAME ‘from’ SOURCE-TYPE \
[;QUERY] \
[;RANGE-QUERY]
其中
ATTR-TYPE 是 ‘uint’ 或 ‘timestamp’之一
SOURCE-TYPE 是 ‘field’, ‘query’, 或 ‘ranged-query’之一
QUERY 是用来取得全部(文档 ID,属性值)序对的 SQL 查询
RANGE-QUERY 是用来取得文档 ID 的最小值与最大值的 SQL 查询,
与’sql_query_range’类似
示例:
sql_attr_multi = uint tag from field;
sql_attr_multi = uint tag from query; SELECT id, tag FROM tags
sql_attr_multi = uint tag from ranged-query; \
SELECT id, tag FROM tags WHERE id>=$start AND id<=$end; \
SELECT MIN(id), MAX(id) FROM tags
使用field类型时,field字段的值应该是以英文逗号隔开的多个无符号32位整数,如:1,2,3,4
使用query或者ranged-query时,每行一个值,一个id对应多个(多行)tag值
使用实例:
先配置sphinx文件
sql_query = SELECT areaid FROM table where status=3
sql_attr_uint = areaid #从SQL读取到的值必须为整数
PHP代码中执行
$sphinx->setFilter(‘areaid’, array(4)); //过滤table中的areaid=4的信息
---------------------
作者:Websites
来源:CSDN
原文:https://blog.csdn.net/websites/article/details/18802015
版权声明:本文为博主原创文章,转载请附上博文链接!
function indexAction(){
$kw = $this->input->get('kw');
//分页
//$p = $this->input->get('p');
$p = (int)$this->input->get('p') > 0 ? (int)$this->input->get('p') : 1;
//var_dump( $this->db );
//$res = $this->db->query( 'select * from crawl_contents limit 10' )->result_array();
App::auto_load('sphinxapi');
$sp = new SphinxClient ();
$host = $this->site['SITE_SEARCH_SPHINX_HOST'];
$port = (int)$this->site['SITE_SEARCH_SPHINX_PORT'];
$name = $this->site['SITE_SEARCH_SPHINX_NAME'];
$start= ($p - 1) * (int)$this->site['SITE_SEARCH_PAGE'];
$limit= (int)$this->site['SITE_SEARCH_PAGE'];
$sp->SetServer($host, $port);
//设置最大搜索时间
$sp->setMaxQueryTime(10);
//设置权重值的范围
$sp->setWeights(array(100,1));
$sp->setLimits( $start , $limit );
$sp->SetMatchMode ( SPH_MATCH_EXTENDED2 );//设置模式
$sp->SetRankingMode ( SPH_RANK_PROXIMITY );//设置评分模式
$sp->SetFieldWeights (array('title'=>$this->site['WEIGHT_TITLE'],'content'=>$this->site['WEIGHT_DES'] ) );//设置字段的权重,如果area命中,那么权重算2
$sortby = '@weight DESC , click DESC ,time DESC ';
$sp->SetSortMode (SPH_SORT_EXTENDED , $sortby);
$res = $sp->query($kw , $name );
echo ' 总共找到 文档数';
var_dump( $res['total'] );
echo ' 搜索用时';
var_dump( $res['time'] );
echo $sp->GetLastError();
//页数
//对结果加颜色
$options = array(
'before_match'=>'',
'after_match'=>'',
);
$p_num = ceil( $res['total']/$limit );
if( $p_num >=1 ){
for( $i = 1 ; $i <= $p_num ; $i++ )
$pageurl[] = $this->site['SITE_SEARCH_URLRULE'] ? str_replace('{id}', urlencode($kw), $this->site['SITE_SEARCH_URLRULE']) : url('search/index', array('kw' => urlencode($kw), 'p' => $i));
} else {
$pageurl[] = '';
}
$row = array();
if( $p_num >= $p ){
$ids = join( ',' , array_keys( $res['matches'] ) );
$sql = 'SELECT id , title , des , md5_url , type , url ,time , click FROM docs where id IN ('. $ids . ') ORDER BY field(id,' .$ids . ')' ;
$docs = $this->db->query( $sql )->result_array();
foreach ($docs as $doc) {
$title[] = $doc['title'];
$des[] = $doc['des'];
}
$title = $sp->buildExcerpts($title , 'ind_doc1', $kw, $options); //高亮tilte 和des
$des = $sp->buildExcerpts($des , 'ind_doc1', $kw, $options);
// var_dump( $title );
// var_dump( $des );
foreach ($docs as $key => $value) { //循环重新复制给 title 和 des
$docs[$key]['title'] = $title[$key];
$docs[$key]['des'] = $des[$key];
}
} else {
echo "没有内容了!";
}
$this->view->assign('kw',$kw);
$this->view->assign('searchdata',$docs);
$this->view->assign('pageurl',$pageurl);
$this->view->display('search');
}
---------------------
作者:hani1990
来源:CSDN
原文:https://blog.csdn.net/liumeng305/article/details/47255309
版权声明:本文为博主原创文章,转载请附上博文链接!
重建主索引和增量索引:
[plain] view plain copy
/usr/local/coreseek/bin/indexer--config /usr/local/coreseek/etc/csft.conf -rotate index_main
/usr/local/coreseek/bin/indexer--config /usr/local/coreseek/etc/csft.conf -rotate index_add
合并建主索引和增量索引:
[plain] view plain copy
indexer --config /usr/local/coreseek/etc/csft.conf --merge index_main index_add --merge-dst-range deleted 0 0 -rotate
重建整个索引:
[plain] view plain copy
/usr/local/coreseek/bin/indexer --config /usr/local/coreseek/etc/csft.conf --rotate --all
当我们第一次使用indexer为表中内容建立索引后,当前表中内容都可以通过sphinxapi查询到。但是,当我们增加记录后,sphinx还未为增加的记录建立索引;修改记录后,应该为修改后记录重新建立索引;删除记录后,应该从索引文件中将该记录删除。以下,本文分别介绍这三种情况的处理方法。
我们可以建立一张表,专门用于存放已经建立索引的最大主键id值;比如:第一次建立索引后,记录数据库表中最大id为max_id=100,当向数据库中添加10条新纪录后,数据库表中最大主键id变为了110。因此,我们只需要为大于max_id的这10条记录建立索引。
为此,我们可以再配置一个数据源和一个索引,定期执行,用于为新增记录建立索引。
//记录已更新记录的最大id
create table rain_newszl
(
max_id int unsigned
);
#新闻增量数据源
source news_zl
{
type = mysql
sql_host =localhost
sql_user =root
sql_pass =root
sql_db =rain
sql_port =3306
sql_query_pre =SET NAMES utf8
#从数据库表查询id大于max_id的记录,以及修改记录表rain_newsupdate中所有记录,为其建立索引
sql_query = select id,title,content from rain_news where id > (select max_id from rain_newszl)
#将rain_newszl表中记录的值更改为最大的id
sql_query_post = update rain_newszl set max_id = (select id from rain_news order by id desc limit 1)
}
index news_zl
{
source =news_zl
path =D:\wamp\coreseek\var\data\newszl
docinfo =extern
mlock =0
morphology =none
min_word_len =1
html_strip =0
charset_dictpath =D:\wamp\coreseek\etc
charset_type =zh_cn.utf-8
}
D:\wamp\coreseek\bin\indexer.exe -c D:\wamp\coreseek\etc\sphinx.conf news_zl --rotate //为增量记录建立索引
D:\wamp\coreseek\bin\indexer.exe -c D:\wamp\coreseek\etc\sphinx.conf --merge news news_zl --rotate //将增量索引和原索引合并
增量索引通过上面三个步骤就可以完成。
为修改的记录重新建立索引,同增加记录一样,需要新建一个表,存储修改记录的id,再为该表中所有记录重新建立索引,合并到原索引文件中。也分为三个步骤,这里在增加记录的基础上进行修改。
//记录修改的id
create table rain_newsupdate
(
id int unsigned
)engine=innodb charset=utf8;
命令行执行跟增加记录中一样,没有修改
对于删除记录,就要修改四处位置。
在表中添加一列isdeleted,用于标识记录是否删除(其实在数据库中,该列没什么用处,主要是在sphinx索引文件中作为属性使用)
alter table rain_news add column isdeleted int default 0;
在原配置文件和增量配置文件中都要添加这句话sql_attr_uint = isdeteled(在索引文件中声明isdeleted是一个属性,可以进行过滤),同时查询语句中也要添加该字段。
D:\wamp\coreseek\bin\indexer.exe -c D:\wamp\coreseek\etc\sphinx.conf news_zl --rotate
D:\wamp\coreseek\bin\indexer.exe -c D:\wamp\coreseek\etc\sphinx.conf --merge news news_zl --merge-dst-range isdeleted 0 0 --rotate
//这里--merge-dst-range 前面有介绍
在删除记录时,要更新索引文件中相应记录的isdeleted属性,将值修改为1;
从sphinx中查询带关键词记录id集合时,需要设置过滤,只匹配isdeleted为0的记录;
到此为止,增加、修改、删除记录的索引文件更新都已经完成,对于命令行的命令,可以新建一个批处理,定时执行即可。
---------------------
作者:zuimei_forver
来源:CSDN
原文:https://blog.csdn.net/zuimei_forver/article/details/49951299
版权声明:本文为博主原创文章,转载请附上博文链接!
一、增量索引处理
0、网上示例http://blog.csdn.net/ms_x0828/article/details/7679229
1、注意修改配置文件
2、自己到数据表中增加测试数据
3、增量索引生成 /usr/local/coreseek/bin/indexer -c/www/cnpatent/index/cnpatentdelta.conf delta --rotate
4、合并索引 /usr/local/coreseek/bin/indexer-c /www/cnpatent/index/cnpatentdelta.conf --merge cnpatent delta --rotate--merge-dst-range deleted 0 0
5、注意合并索引时要保证索引在后台运行,不然会报错
6、测试
一:Sphinx(coreseek)的查询默认最大记录数是:1000,而我们想更改这个数值。就需要更改二个地方。
1是更改csft.conf(如果是sphinx就是sphinx.conf)配置文件的:max_matches = 10000 #后面数字就是你想查询的最大记录数。建议在1000~10000之内。
2是在api调用时,$cl->SetLimits($pageStart, $pageSize, $max_limits);用SetLimits的第三个参数更改为你想要的显示最大记录数。
经过这二个配置和程序更改,你再查询看看呢!(注意你搜索要有这么多记录哦。呵)
二:sphinx的高亮。
开始按程序来设置高亮,都是没问题的。因为都是英文嘛。问题点主要是出现在中文的高亮上面。我的页面和数据库都是gbk编码。
所以做了如下配置和程序更改。
$opts = array(
"before_match" => "",
"after_match" => "",
"chunk_separator" => "..",
"limit" => 10,
"around" => 3
);
//$docs必须是数组传进来哦
function search_highlight($docs) {
$this->s_keywords = iconv('gbk', 'utf-8', $this->s_keywords);
$docs[0] = iconv('gbk', 'utf-8', $docs[0]);
$arr_words = $this->h_cl->BuildExcerpts ( $docs, $this->s_index, $this->s_keywords, $this->h_opts);
$arr_words[0] = iconv('utf-8', 'gbk', $arr_words[0]);
$this->s_keywords = iconv('utf-8', 'gbk', $this->s_keywords);
return $arr_words;
}
至此,中文高亮就显示正常了
三:搜索排序
默认我用了:$cl->SetMatchMode(SPH_SORT_RELEVANCE);,
而我如果想把最新的结果显示在前面,必须要用SPH_SORT_TIME_SEGMENTS模式。
所以我在配置文件里加上了:sql_attr_timestamp = add_time
在程序中就加上了:$cl->SetSortMode(SEGMENTS, 'add_time');
这样就正常了!
---------------------
作者:兄弟连_战地日记
来源:CSDN
原文:https://blog.csdn.net/lampzdrj/article/details/10599965
版权声明:本文为博主原创文章,转载请附上博文链接!
最近组里同事开发项目时遇到一个Sphinx的问题,表面上看起来没有问题的代码,实际运行时却总是无法的到正常的结果。
我看了一下,主要的代码片段如下:
//高亮显示的配置参数的数组
$opts = array(
"before_match" => "",
"after_match" => "",
"chunk_separator" => "...",
"limit" => 60,
"around" => 25,
"single_passage" => true,
"exact_phrase" => false
);
......
//高亮显示
$highlight_name_array = search_highlight( $name_docs, $index, $words, $opts );
$highlight_description_array = search_highlight( $description_docs, $index, $words, $opts );
......
function search_highlight( $docs, $index, $words, $opts ) {
$cl = new SphinxClient ();
$arr_words = $cl->BuildExcerpts ( $docs, $index, $words, $opts );
return $arr_words;
}
遇到的情况却是标题里的高亮显示没有问题,但是介绍里的高亮却总是没有办法出来。
经过反复调试,发现和参数传递,过程处理,字符编码都没有关系,得到的结果在第二句search_highlight处理时总是固执的没有任何变化。
后来又把问题放在了参数设置上,将single_passage、exact_phrase两个参数去掉,替换before_match、after_match,都没有得到任何的成效。
一筹莫展时,突然看到了around这个参数,一般我们都设置为3,而这里设置为30,把这个参数改一改试试,发现It works!
经过调试,发现around值为25的时候能满足功能和产品的需求。
这个问题可能是Sphinx的一个bug,在某些特定条件下高亮的截取会失败,在有时间的时候我会阅读源码来调查这个问题的产生根源。
---------------------
作者:蒋宇捷
来源:CSDN
原文:https://blog.csdn.net/hfahe/article/details/5494776
版权声明:本文为博主原创文章,转载请附上博文链接!
怎么让搜索出的结果关键字显示,要用到sphinx里的BuildExcerpts方法:
在控制器里添加如下代码:
control(welcome.php):
public function make()
{
$this->load->helper('sphinxapi_helper');
$key=$this->input->post('keyword');
$sphinx = new SphinxClient();//sphinx的主机名和端口
$sphinx->SetServer ( 'localhost', 9312 );//设置返回结果集为php数组格式
$sphinx->SetArrayResult ( true );
$sphinx->SetLimits(0, 20, 1000);//最大搜索时间
$sphinx->SetMaxQueryTime(10);
$result = $sphinx->query($key,"email");
$opts = array(
"before_match" => "",
"after_match" => "",
"chunk_separator" => "...",
"limit" => 20,
"around" => 25,
"single_passage" => true,
"exact_phrase" => false
);
$words =$key;
$index = "email";
$con="";
$title="";
$comman="";
if(isset($result['matches'])&&$result['matches']!="")
{
foreach($result['matches'] as $v){
$title.=$comman.$v['attrs']['title'];
$con.=$comman.$v['attrs']['content'];
$comman="|&|";
}
$ti=explode("|&|",$title);
$re=explode("|&|",$con);
$data['content']=$sphinx->BuildExcerpts ($re, $index, $words, $opts );
$data['title']=$sphinx->BuildExcerpts ($ti, $index, $words, $opts );
$this->load->view('view',$data);
}
else{echo '没有搜索到你需要的内容'; }
}
view(view.php):
for($i=0;$i
echo $title[$i].'
';
echo $content[$i].'
';
}
?>
关键字高亮显示完成!
---------------------
作者:hxy_jci
来源:CSDN
原文:https://blog.csdn.net/hxy_jci/article/details/9110019
版权声明:本文为博主原创文章,转载请附上博文链接!