You may want to have a look at Lucene. It's written in Java but you can use it from PHP through either its Zend port or Solr, although I think Solr might not be a solution since you probably want something embedded within your CMS.
The idea is that you can build an index from all the searchable data and then search that index. It has the advantage that it can be much faster than database queries. You can also implement a scoring system, so that some records show up higher in the results list if they are more relevant to the user. One possible downside is that you have to update the index each time the data is updated.
If the Lucene approach doesn't fit your scenario, you could go with a mix of PHP and database code. A view or a stored procedure could act as a surrogate index, aggregating the searchable data. You'd need to split strings by whitespaces and this could make it rather slow, but will get you there. The PHP code will be responsible for building the WHERE clause (you can have a look at how Solr implements query strategies for suggestions as source of inspiration). Assuming you have Id
, Name
and Score
as index fields and two contact records with Id=1, FirstName="Ric", LastName="Flair"
and Id=2, FirstName="Ric", LastName="Flare"
the index records would be looking something like this:
+--------------+-------+
| Id | Name | Score |
+----+---------+-------+
| 1 | Ric | 1 |
+----+---------+-------+
| 1 | Flair | 1 |
+----+---------+-------+
| 2 | Ric | 1 |
+----+---------+-------+
| 2 | Flare | 1 |
+----+---------+-------+
An example could look like this (SQL Server):
DECLARE @index TABLE (
Id INT NOT NULL,
Name NVARCHAR(50) NOT NULL,
Score INT NOT NULL
)
INSERT INTO @index (Id, Name, Score) VALUES (1, 'Ric', 1)
INSERT INTO @index (Id, Name, Score) VALUES (1, 'Flair', 1)
INSERT INTO @index (Id, Name, Score) VALUES (2, 'Ric', 1)
INSERT INTO @index (Id, Name, Score) VALUES (2, 'Flare', 1)
SELECT
Id,
SUM(Score) AS Score
FROM
@index
WHERE
Name = 'Ric'
OR Name = 'Flair'
GROUP BY
Id
ORDER BY
Score DESC
Ric Flair
would have a higher score since it matches on both values, thus popping first in the search results.
The index could also contain title and summary fields to be used as values to be displayed in the search results page. Or you could join the results with a view that preselects those values.
You can toy around with the conditions in the WHERE
clause or with the Score
field (you could give different scores to different type of records or properties) to get a more refined search experience.
I would go for the following UserSearches table:
UserId
Date
Then I add a column for each field
This way, you can easily SELECT the columns you want to consider, then group / sum the data.
A business case you may encounter : How many different user searched for a price over 20000:
SELECT count(UserId)
FROM (SELECT UserId, SUM(price)
FROM UserSearches
WHERE price > 20000
GROUP BY price)
It seems pretty straightforward to me.
The count is not needed. You don't have an history if you don't have a Date associated to every search.
Your Field column is going to be problematic. Your table is supposed to make you store normalized data, not key-value pairs.
EDIT (to answer your comment)
If you add a field to your search, add a column, existing data will have NULL for this column. You loose a bit of info which is the 'context' of your search (what fields where available at the time). If it is relevant for you to keep the context of every search set the defaut value to "N/A" meaning "Not available at the time". It doesn't seem very clean (you might need to exclude the "N/A" value often) but it's flexible.
Best Answer
You can use the
+
or-
signs to add or remove weight for a search term.However the best place to search really isn't google at all, it's StackOverflow
A few google examples anyway:
+C
for articles where the letter C stands alone+C -C++
for C articles where there are no references to C+++"C Sharp"
for articles with weight added to a grouped term