2008-12-31 17 views
13

Necesito buscar entre varias columnas de dos tablas en mi base de datos usando Búsqueda de texto completo. Las dos tablas en cuestión tienen indexadas las columnas relevantes de texto completo.Uso de la búsqueda de texto completo en SQL Server 2008 en varias tablas, columnas

La razón por la que estoy optando por la búsqueda de texto completo: 1. Ser capaz de buscar palabras con acento fácilmente (CAFE) 2. Ser capaz de clasificar de acuerdo a la proximidad de textos, etc. 3. "Did ¿Te refieres a XXX? funcionalidad

Aquí es una estructura de tabla ficticia, para ilustrar el desafío:

 
Table Book 
BookID 
Name (Full-text indexed) 
Notes (Full-text indexed) 

Table Shelf 
ShelfID 
BookID 

Table ShelfAuthor 
AuthorID 
ShelfID 

Table Author 
AuthorID 
Name (Full-text indexed) 

tengo que buscar a través de Nombre de libro, Notas de libro y el nombre del autor.

Conozco dos maneras de lograr esto:

  1. El uso de un índice de texto completo Ver: Esto habría sido mi método preferido, pero no puedo hacer esto porque para una vista para ser indexado en texto completo, necesita ser enlazado, no tener ninguna unión externa, tener un índice único. La vista que necesitaré para obtener mis datos no cumple estas restricciones (contiene muchas otras tablas unidas de las que necesito obtener datos).

  2. Usando join en un procedimiento almacenado: El problema con este enfoque es que necesito tener los resultados ordenados por rango. Si estoy realizando varias uniones en las tablas, SQL Server no buscará en múltiples campos de forma predeterminada. Puedo combinar dos consultas CONTAINS individuales en las dos tablas vinculadas, pero no sé de una manera de extraer el rango combinado de las dos consultas de búsqueda. Por ejemplo, si busco 'Arthur', los resultados tanto de la consulta del libro como de la consulta del autor deben tenerse en cuenta y ponderarse en consecuencia.

+0

Para el n. ° 1, donde dices que te estás uniendo ... ¿realmente eres EXTRAORDINARIO? eso es un producto cartesiano y dudo que realmente lo estés haciendo. Una unión interna o izquierda/derecha está bien. –

+0

No estoy usando una OUTER JOIN para ninguna de las tablas mostradas. Hay otras tablas que necesito para IZQUIERDA OUTER JOIN, porque es posible que no tengan ninguna fila FKed. –

Respuesta

14

Usando FREETEXTTABLE, sólo tiene que diseñar algún algoritmo para calcular el rango fusionada en cada resultado tabla unida. El siguiente ejemplo sesga el resultado hacia éxitos de la tabla de libros.

SELECT b.Name, a.Name, bkt.[Rank] + akt.[Rank]/2 AS [Rank] 
FROM Book b 
INNER JOIN Author a ON b.AuthorID = a.AuthorID 
INNER JOIN FREETEXTTABLE(Book, Name, @criteria) bkt ON b.ContentID = bkt.[Key] 
LEFT JOIN FREETEXTTABLE(Author, Name, @criteria) akt ON a.AuthorID = akt.[Key] 
ORDER BY [Rank] DESC 

Tenga en cuenta que simplifiqué su esquema para este ejemplo.

+0

Perdóneme si me equivoco, pero ¿no significa que los resultados solo se mostrarán para la tabla Autor si también se encuentra un AutorID en uno de los resultados de fila para Libros? –

+0

Eso es verdad. Si es el caso de que aparezcan autores que no tienen libros, deberá ajustar las uniones en consecuencia. – Ishmael

+2

No estoy seguro de qué tan factible sea el diseño de algún algoritmo para calcular el rango fusionado. [Documentation] (https://technet.microsoft.com/en-us/library/cc879245.aspx) dice: "Los valores de rango indican ** solo un orden relativo de relevancia de las filas en el conjunto de resultados **, con un valor inferior que indica una menor relevancia. Los valores reales no son importantes y, por lo general, difieren cada vez que se ejecuta la consulta ". Tendría que normalizar la fórmula de rango (OKAPI BM25) que parece dudosa dado que los valores de rango absoluto cambiarán con las estadísticas del índice subyacente. – Serguei

1

Utilizaría un procedimiento almacenado. El método de texto completo o lo que sea devuelve un rango que puede ordenar. No estoy seguro de cómo se compararán entre sí, pero estoy seguro de que podrías jugar un rato y resolverlo. Por ejemplo:

Select SearchResults.key, SearchResults.rank From FREETEXTTABLE(myColumn, *, @searchString) as SearchResults Order By SearchResults.rank Desc 
3

No creo que la respuesta aceptada resuelva el problema. Si intenta buscar todos los libros de un autor determinado y, por lo tanto, usa el nombre del autor (o parte de él) como criterio de búsqueda, los únicos libros devueltos por la consulta serán aquellos que tengan los criterios de búsqueda en su propio nombre. .

La única forma en que veo este problema es replicar las columnas del Autor que desea buscar en la tabla Libro e indexar esas columnas (o columna ya que probablemente sería inteligente almacenar la información relevante del autor en un XML columna en la tabla Libro).

1

FWIW, en una situación similar, nuestro DBA creó desencadenadores DML para mantener una tabla dedicada de búsqueda de texto completo. No fue posible usar una vista materializada debido a sus muchas restricciones.

3

que tenían el mismo problema que tú, pero en realidad participaron 10 mesas (una tabla de usuarios y varios otros de información)

hice mi primera consulta utilizando FREETEXT en la cláusula WHERE para cada mesa, pero la consulta estaba tomando demasiado tiempo.

Luego vi varias respuestas sobre el uso de FREETEXTTABLE en su lugar y la comprobación de valores no nulos en la columna de clave para cada tabla, pero también tardó mucho en ejecutarse.

me fijo mediante el uso de una combinación de FREETEXTTABLE y UNION selecciona:

SELECT Users.* FROM Users INNER JOIN 
(SELECT Users.UserId FROM Users INNER JOIN FREETEXTTABLE(Users, (column1, column2), @variableWithSearchTerm) UsersFT ON Users.UserId = UsersFT.key 
UNION 
SELECT Table1.UserId FROM Table1 INNER JOIN FREETEXTTABLE(Table1, TextColumn, @variableWithSearchTerm) Table1FT ON Table1.UserId = Table1FT.key 
UNION 
SELECT Table2.UserId FROM Table2 INNER JOIN FREETEXTTABLE(Table2, TextColumn, @variableWithSearchTerm) Table2FT ON Table2.UserId = Table2FT.key 
... --same for all tables 
) fts ON Users.UserId = fts.UserId 

Esto resultó ser increíblemente mucho más rápido.

Espero que ayude.

0

Esta respuesta ya ha vencido, pero una forma de hacerlo si no puede modificar tablas primarias es crear una nueva tabla con los parámetros de búsqueda agregados a una columna.

A continuación, cree un índice de texto completo en esa columna y consulte esa columna.

Ejemplo

SELECT 
    FT_TBL.[EANHotelID]     AS HotelID, 
    ISNULL(FT_TBL.[Name],'-')   AS HotelName, 
    ISNULL(FT_TBL.[Address1],'-')  AS HotelAddress, 
    ISNULL(FT_TBL.[City],'-')   AS HotelCity, 
    ISNULL(FT_TBL.[StateProvince],'-') AS HotelCountyState, 
    ISNULL(FT_TBL.[PostalCode],'-')  AS HotelPostZipCode, 
    ISNULL(FT_TBL.[Latitude],0.00)  AS HotelLatitude, 
    ISNULL(FT_TBL.[Longitude],0.00)  AS HotelLongitude, 
    ISNULL(FT_TBL.[CheckInTime],'-') AS HotelCheckinTime, 
    ISNULL(FT_TBL.[CheckOutTime],'-') AS HotelCheckOutTime, 
    ISNULL(b.[CountryName],'-')   AS HotelCountry, 
    ISNULL(c.PropertyDescription,'-') AS HotelDescription, 
    KEY_TBL.RANK 

    FROM [EAN].[dbo].[tblactivepropertylist] AS FT_TBL INNER JOIN 
    CONTAINSTABLE ([EAN].[dbo].[tblEanFullTextSearch], FullTextSearchColumn, @s) 
     AS KEY_TBL 
    ON FT_TBL.EANHotelID = KEY_TBL.[KEY] 
    INNER JOIN [EAN].[dbo].[tblCountrylist] b 
    ON FT_TBL.Country = b.CountryCode 
    INNER JOIN [EAN].[dbo].[tblPropertyDescriptionList] c 
    ON FT_TBL.[EANHotelID] = c.EANHotelID 

En el código anterior [EAN]. [Dbo]. [TblEanFullTextSearch], FullTextSearchColumn es la nueva tabla y columna con los campos añadidos, ahora se puede hacer una consulta sobre la nueva tabla con combinaciones a la tabla desde la que desea mostrar los datos.

Espero que esto ayude

Cuestiones relacionadas