【发布时间】:2019-07-05 10:07:43
【问题描述】:
我有一种情况需要超快速的全文通配符搜索。
以前我只使用一个 SQL 存储过程,它可以对具有多个连接的表执行搜索,并使用带有 LIKE '%searchTerm%' 的查询,但是它在几百万条记录上非常慢。
我尝试过在 SQL 中进行全文索引和搜索,但是,这似乎不起作用,因为它会中断单词,但我需要搜索字符串的中间。
更改为一个新的 SQL 存储过程,它将所有搜索字段连接到一个字符串中,并将其与对象 ID 的另一列一起返回——然后将整个对象缓存为 C# 中的 List<>(特别是作为AppPool 中的静态对象)并使用检查搜索字符串的 IndexOf() 的逻辑似乎大大提高了性能(从大约 10 秒到大约 100 毫秒)。
我担心这是否是一种糟糕的方法,或者是否有更好的方法?
创建与对象 ID 关联的搜索字符串的新 SQL 存储过程如下;
CREATE PROCEDURE [dbo].[Search_GetLookupTable]
AS
BEGIN
SELECT
ObjectId,
(Name + ' ' + OtherName + ' ' + ep.SomethingElse + ISNULL(
(
SELECT
' ' + twl.SomeBindingName
FROM
TableWithLotsOfBindings twl
WHERE
twl.ObjectId = e.ObjectId
FOR XML PATH('')
)
, '')) AS SearchString,
ep.LastActionDateTime AS OrderDate
FROM
ObjectTable e
INNER JOIN ObjectMetaData ep ON ep.ObjectId = e.ObjectId
END
GO
然后将其加载到具有ObjectId 和SearchString 的模型的List<> 中。然后我将其保存到搜索 class 中的 static 属性中,然后跟踪最后一次加载 DateTime 并每 10 分钟左右回收一次。
我最初也将它保存到分布式内存缓存中,但是序列化和传输数据的性能很差。
private static readonly List<GlobalSearchLookupModel> _CachedSearchLookupModel = new List<GlobalSearchLookupModel>();
private static DateTime _CacheSearchLookupModelDateTime = DateTime.MinValue;
List<GlobalSearchLookupModel> lookupModels = _CachedSearchLookupModel.Value;
if (lookupModels == null)
{
lookupModels = SqlClass.SearchLookupTable();
_CachedSearchLookupModel.Value.Clear();
_CachedSearchLookupModel.Value.AddRange(lookupModels);
_CachedSearchLookupModelDateTime = DateTime.UtcNow;
}
if (_CacheSearchLookupModelDateTime.AddMinutes(10) <= DateTime.UtcNow)
{
_CachedSearchLookupModelDateTime = DateTime.UtcNow;
BackgroundTaskHelper.StartBackgroundTask(
"Pre-Load Global Search Lookup Table",
() =>
{
DateTime asyncPreloadStartDateTime = DateTime.UtcNow;
_CachedSearchLookupModel.Value.Clear();
_CachedSearchLookupModel.Value.AddRange(SqlClass.SearchLookupTable());
_CachedSearchLookupModelDateTime = DateTime.UtcNow;
});
}
List<Int64> ids = lookupModels
.Where(l => l.SearchString.IndexOf(searchTerms, StringComparison.InvariantCultureIgnoreCase) >= 0)
.OrderByDescending(l => l.OrderDate)
.Select(l => l.ObjectId)
.Distinct()
.Take(maxReturn)
.ToList();
【问题讨论】:
-
您是否尝试过使用专门用于全文搜索的非 SQL 解决方案?比如 Elasticsearch 还是纯 Lucene?另外,看看位图索引,如果你索引 ngrams 并且你的文本是自然的(没有散列,垃圾),你可以大大加快速度
-
我还没有尝试过 ElasticSearch 或其他任何东西。我去看看,谢谢。
-
你能详细说明为什么全文索引不起作用?
-
@Steve 全文索引不起作用,因为它不会在
String的中间进行搜索。 SQL 中唯一有效的方法是使用带有LIKE '%term%'的查询 -
@Sivart 我很确定全文索引可以在字符串中间进行搜索。能举个具体的例子吗?
标签: c# sql-server asp.net-web-api search full-text-search