From 19ef6dc90739edcfb7aedb8277d91988ce47f6cf Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Fri, 24 Aug 2018 11:14:35 +0200 Subject: [PATCH] SONAR-11134 Change the doc search ranking algorithm --- .../components/SearchResultEntry.tsx | 3 ++- .../components/SearchResults.tsx | 18 +++++++++++++++-- .../__tests__/SearchResultEntry-test.tsx | 20 ++++++++++++++----- .../SearchResultEntry-test.tsx.snap | 2 ++ .../__snapshots__/SearchResults-test.tsx.snap | 2 ++ 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/server/sonar-web/src/main/js/apps/documentation/components/SearchResultEntry.tsx b/server/sonar-web/src/main/js/apps/documentation/components/SearchResultEntry.tsx index 613c390d788..436dfb56e95 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/SearchResultEntry.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/SearchResultEntry.tsx @@ -23,8 +23,9 @@ import { Link } from 'react-router'; import { highlightMarks, cutWords, DocumentationEntry } from '../utils'; export interface SearchResult { - page: DocumentationEntry; highlights: { [field: string]: [number, number][] }; + longestTerm: string; + page: DocumentationEntry; } interface Props { diff --git a/server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx b/server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx index 30cfdc9fd94..b42ba425fd9 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx @@ -19,6 +19,7 @@ */ import * as React from 'react'; import lunr, { LunrIndex } from 'lunr'; +import { sortBy } from 'lodash'; import SearchResultEntry, { SearchResult } from './SearchResultEntry'; import { DocumentationEntry } from '../utils'; @@ -51,21 +52,34 @@ export default class SearchResults extends React.PureComponent { .map(match => { const page = this.props.pages.find(page => page.relativeName === match.ref); const highlights: { [field: string]: [number, number][] } = {}; + let longestTerm = ''; + // remember the longest term that matches the query *exactly* Object.keys(match.matchData.metadata).forEach(term => { + if ( + query.toLowerCase().includes(term.toLowerCase()) && + longestTerm.length < term.length + ) { + longestTerm = term; + } + Object.keys(match.matchData.metadata[term]).forEach(fieldName => { const { position: positions } = match.matchData.metadata[term][fieldName]; highlights[fieldName] = [...(highlights[fieldName] || []), ...positions]; }); }); - return { page, highlights }; + return { page, highlights, longestTerm }; }) .filter(result => result.page) as SearchResult[]; + // re-order results by the length of the longest matched term + // the longer term is the more chances the result is more relevant + const sortedResults = sortBy(results, result => -result.longestTerm.length); + return ( <> - {results.map(result => ( + {sortedResults.map(result => ( { it('should render', () => { expect( - shallow() + shallow( + + ) ).toMatchSnapshot(); }); }); @@ -44,24 +46,32 @@ describe('SearchResultEntry', () => { describe('SearchResultText', () => { it('should render with highlights', () => { expect( - shallow() + shallow( + + ) ).toMatchSnapshot(); }); it('should render without highlights', () => { - expect(shallow()).toMatchSnapshot(); + expect( + shallow() + ).toMatchSnapshot(); }); }); describe('SearchResultTitle', () => { it('should render with highlights', () => { expect( - shallow() + shallow( + + ) ).toMatchSnapshot(); }); it('should render not without highlights', () => { - expect(shallow()).toMatchSnapshot(); + expect( + shallow() + ).toMatchSnapshot(); }); }); diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResultEntry-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResultEntry-test.tsx.snap index 7a2b86c3590..3be4c54be97 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResultEntry-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResultEntry-test.tsx.snap @@ -11,6 +11,7 @@ exports[`SearchResultEntry should render 1`] = ` result={ Object { "highlights": Object {}, + "longestTerm": "", "page": Object { "content": "", "order": -1, @@ -25,6 +26,7 @@ exports[`SearchResultEntry should render 1`] = ` result={ Object { "highlights": Object {}, + "longestTerm": "", "page": Object { "content": "", "order": -1, diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResults-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResults-test.tsx.snap index 69473caa244..cc6081342c8 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResults-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResults-test.tsx.snap @@ -21,6 +21,7 @@ exports[`should search 1`] = ` ], ], }, + "longestTerm": "from", "page": Object { "content": "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words.", "order": -1, @@ -44,6 +45,7 @@ exports[`should search 1`] = ` ], ], }, + "longestTerm": "from", "page": Object { "content": "Foobar is a universal variable understood to represent whatever is being discussed.", "order": -1, -- 2.39.5